Browse Source

fix: Utils.isInsideBox的frustum建立有误

xzw 2 years ago
parent
commit
beafa4834e

+ 36 - 13
src/ExtendPointCloudOctree.js

@@ -580,13 +580,14 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
     } 
      
 
+ 
 
     updateBound(){
-        var boundingBox_ = this.pcoGeometry.tightBoundingBox.clone().applyMatrix4(this.matrixWorld)
+        var boundingBox_ = this.pcoGeometry.tightBoundingBox.clone().applyMatrix4(this.matrixWorld)//tightBoundingBox是点云原始的bound,但经过(绕z)旋转后bound有所改变,比之前体积更大。
         this.bound = boundingBox_
         this.bound2 = this.getBoundWithPanos()
     } 
-    getBoundWithPanos(){//确保pano在内的bound 
+    getBoundWithPanos(){//确保panoBound在内的bound 
         let bound = this.bound.clone()
         this.panos.forEach(pano=>{
             let panoBound = new THREE.Box3
@@ -597,7 +598,7 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
         return bound
     }
     
-    getPanosBound(){
+    getPanosBound(){//仅由所有pano构成的bound
         if(this.panos.length > 0){
             let minSize = new THREE.Vector3(1,1,1)
             this.panosBound = math.getBoundByPoints(this.panos.map(e=>e.position), minSize)
@@ -629,18 +630,40 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
             ].map(e=>e.applyMatrix4(this.matrixWorld)) 
     } 
      
+    getVolume(){
+        /* var points = this.getUnrotBoundPoint()       -----在只绕z轴旋转时这么写也行
+        var area = Math.abs(math.getArea(points))
+        return area * (this.bound.max.z - this.bound.min.z) */
+        let bound = this.pcoGeometry.tightBoundingBox.clone()
+        let size = bound.getSize(new THREE.Vector3)
+        return size.x * size.y * size.z
+    }
     
-    
-    ifContainsPoint(pos){
-        if(!this.bound || !this.bound.containsPoint(pos))return
+    ifContainsPoint(pos){//pos是否坐落于tightBound内
+        /* if(!this.bound || !this.bound.containsPoint(pos))return   ---这样写也行
         var points = this.getUnrotBoundPoint()
-        return math.isPointInArea(points, null, pos)  
+        return math.isPointInArea(points, null, pos)   */
+        //要把tightBoundingBox想象成一个volumeBox
+        let box = this.pcoGeometry.tightBoundingBox  
+        let center = box.getCenter(new THREE.Vector3)
+        let size = box.getSize(new THREE.Vector3)
+        let boxMatrix = new THREE.Matrix4().setPosition(center.x,center.y,center.z);
+        boxMatrix.scale(size);
+        boxMatrix.premultiply(this.matrixWorld)
+      
+        return Potree.Utils.isIntersectBox(pos, boxMatrix) 
     } 
-     
-    getVolume(){
-        var points = this.getUnrotBoundPoint()
-        var area = Math.abs(math.getArea(points))
-        return area * (this.bound.max.z - this.bound.min.z)
-    }  
+ 
+    
+    intersectBox(boxWorldMatrix){
+        
+        let boxM = boxWorldMatrix.clone().premultiply(this.matrixWorld.clone().invert()); //box乘上点云逆矩阵  (因为点云的忽略掉其matrixWorld, 为了保持相对位置不变,box要左乘matrixWorld的逆)(因第一个参数bound不好变形,第二个参数box可以)
+          
+        return Potree.Utils.isIntersectBox(this.pcoGeometry.tightBoundingBox, boxM)     
+    }
+    
+    
+    
+    
     
 }

+ 6 - 4
src/LRU.js

@@ -14,13 +14,13 @@ class LRUItem{
  */
 class LRU{
 
-	constructor(){
+	constructor(){ //类似链表存储
 		// the least recently used item
 		this.first = null;
 		// the most recently used item
 		this.last = null;
 		// a list of all items in the lru list
-		this.items = {};
+		this.items = {};  //按node的id存储。(id为0的就是root,name='r')
 		this.elements = 0;
 		this.numPoints = 0;
 	}
@@ -33,7 +33,7 @@ class LRU{
 		return this.items[node.id] == null;
 	}
 
-	touch(node){
+	touch(node){//链接node,并且永远放在最后.  (每次updatePointClouds都要刷新一次链表)
 		if (!node.loaded) {
 			return;
 		}
@@ -70,7 +70,7 @@ class LRU{
 				}
 			} else if (item.next === null) {
 				// handle touch on last element
-			} else {
+			} else {//从原来的位置挑出放最后
 				// handle touch on any other element
 				item.previous.next = item.next;
 				item.next.previous = item.previous;
@@ -82,6 +82,8 @@ class LRU{
 		}
 	}
 
+    //因为需要显示的都放末尾,所以不显示的部分都在前面,删除时从头删除。(但并不代表开头的一定是不显示的,所以如果第一个仍是显示的,它很可能是root,也就是name='r'的nodeGeo,删除它也就会删除全部)
+     
 	remove(node){
 		let lruItem = this.items[node.id];
 		if (lruItem) {

+ 20 - 19
src/custom/modules/clipModel/Clip.js

@@ -239,9 +239,9 @@ var Clip = {
             transformation_matrix: visiPointclouds.map((cloud)=>{
                 let data = {
                     id: cloud.dataset_id, 
-                    matrix : this.getTransformationMatrix(cloud).elements, 
-                    //VisiMatrixes:[],
-                    //UnVisiMatrixes:[],
+                    matrix : this.getTransformationMatrix(cloud).elements, //剪裁大框
+                    VisiMatrixes: cloud.material.clipBoxes_in.map(e=>this.getTransformationMatrix(cloud, e.inverse).elements), //若干个可见型小框
+                    UnVisiMatrixes: cloud.material.clipBoxes_out.map(e=>this.getTransformationMatrix(cloud, e.inverse).elements), //若干个不可见型小框
                     modelMatrix:(new THREE.Matrix4).copy(cloud.transformMatrix).transpose().elements
                 }  
                 return data
@@ -279,21 +279,17 @@ var Clip = {
     },
     
     
-    getTransformationMatrix:function(pointcloud) {//剪裁矩阵
-        var invMatrix = new THREE.Matrix4().getInverse(this.box.matrixWorld) 
+    getTransformationMatrix:function(pointcloud, invMatrix) {//剪裁矩阵
+        var invMatrix = invMatrix || new THREE.Matrix4().getInverse(this.box.matrixWorld) 
         return (new THREE.Matrix4).multiplyMatrices(invMatrix, pointcloud.transformMatrix).transpose()
     },
 
 
-    getIntersectPointcloud(){ 
+    /* getIntersectPointcloud(){ 
         var boxBound = new THREE.Box3(
             new THREE.Vector3(-0.5,-0.5,-0.5), new THREE.Vector3(0.5,0.5,0.5),
         ).applyMatrix4(this.box.matrixWorld)    //large boundingbox
-        
-       /*  var boxTightPoints = this.box.children[0].geometry.vertices.map(e=>e.clone().applyMatrix4(this.matrixWorld)) 
-            console.log(boxTightPoints) 
-        */
-        
+         
         let boxMatrixInverse = new THREE.Matrix4().copy(this.box.matrixWorld).invert();
 
         let boxPoints = [
@@ -313,7 +309,7 @@ var Clip = {
             if(rings.length > 1 )return false
 
             {//再用frustum和数据集的sphere相交试试,能排除一些错误
-                let a = Potree.Utils.isInsideBox(points,  boxMatrixInverse) 
+                let a = Potree.Utils.isIntersectBox(points,  this.box.matrixWorld) 
                 if(!a){
                     console.log('没能经过isInsideBox测试')
                 }
@@ -321,17 +317,22 @@ var Clip = {
             }
             return true 
             
-        }
-
-        
-
+        } 
 
         return viewer.scene.pointclouds.filter(e=>intersect(e)) 
-        
-       
+         
 
-    }
+    }  */ 
+    
     
+    getIntersectPointcloud(){ 
+          
+        var intersect = (pointcloud)=>{
+            if(pointcloud.intersectBox(this.box.matrixWorld))return true   
+        } 
+
+        return viewer.scene.pointclouds.filter(e=>intersect(e))  
+    } 
     
    
     /* 

+ 13 - 6
src/custom/objects/Reticule.js

@@ -78,7 +78,7 @@ export default class Reticule extends THREE.Mesh{
         
          
         
-        viewer.setObjectLayers(this, 'sceneObjects' )
+        viewer.setObjectLayers(this,  'sceneObjects' )
     }
 
     judgeTex(){ 
@@ -173,13 +173,20 @@ export default class Reticule extends THREE.Mesh{
     
         if(viewport.name == 'magnifier' )return
     
-        if(this.hoverViewport && this.hoverViewport.name == 'mapViewport' && viewport != this.hoverViewport){
+        if(this.orthoPos && this.hoverViewport && this.hoverViewport.name == 'mapViewport' && viewport != this.hoverViewport){
             //若是在地图上更新,在其他viewport要隐藏。因为在地图上无法得知高度。     
-            viewer.updateVisible(this, 'hoverMap', false)
+            viewer.updateVisible(this, 'hoverMap', false) 
             return; 
+        } 
+        viewer.updateVisible(this, 'hoverMap', true)
+        
+        if(viewport.name == 'mapViewport'){
+            viewer.setObjectLayers(this,  "bothMapAndScene")
+        }else{//通常地图不显示reticule,只有在特殊编辑时才显示
+            viewer.setObjectLayers(this,  'sceneObjects') 
         }
-        viewer.updateVisible(this, 'hoverMap', true)   
-    
+        
+        
         var matrix = this.matrixMap.get(viewport)
         if(!matrix){ 
             this.updateScale(viewport)
@@ -208,7 +215,7 @@ export default class Reticule extends THREE.Mesh{
             var atMap = !intersect.location
             let location = intersect.location || intersect.orthoIntersect.clone()
             let normal  
-            
+            this.orthoPos = atMap
             
             //地图上要瞬间变化 , 因为要使needRender为true很麻烦
             this.show(atMap ? 0 : 300);

+ 24 - 21
src/custom/objects/tool/Measure.js

@@ -81,14 +81,14 @@ export class Measure extends ctrlPolygon{
         this.area = {value:0,string:''}
          
         
-        if(/* this.closed */  this.showArea  ){
+        if( this.showArea  ){
             this.areaLabel = this.createAreaLabel(); 
             this.add(this.areaLabel) 
         }
         
 		 
         //add:
-        if(this.showArea || this.faceDirection){ //是一个平面上的话
+        if(this.atPlane || this.faceDirection){ //是一个平面上的话
             this.createGuideLine(); 
         }
         if(this.measureType == 'Distance' /* || this.measureType.includes('MulDistance') */){
@@ -806,9 +806,7 @@ export class Measure extends ctrlPolygon{
 
     
     
-    //closed的不一定在同一个平面上,但一般是
-    //showArea 能表示closed且在同一个平面上。虽然按道理反过来并不成立,但在此约定所有在同一平面的closed的都显示面积。
-      
+    
     transformData(prop){
         if(prop.measureType == 'Point'){ 
             prop.showCoordinates = true, 
@@ -816,40 +814,36 @@ export class Measure extends ctrlPolygon{
             prop.maxMarkers = 1,
             prop.minMarkers = 1 
         }else if(prop.measureType == 'Distance'){
-            prop.showDistances = true,  
-            prop.closed = false,
+            prop.showDistances = true,   
             prop.showEdges = true,
             prop.maxMarkers = 2,
             prop.minMarkers = 2 
         }else if(prop.measureType == 'MulDistance'){//new 
             prop.showDistances = true,  
-            prop.closed = false,
             prop.showEdges = true, 
             prop.minMarkers = 2 
         }else if(prop.measureType == 'Ver MulDistance'){ 
-            prop.showDistances = true,  
-            prop.closed = false,
+            prop.showDistances = true,
+            prop.atPlane = true,                
             prop.showEdges = true, 
             prop.minMarkers = 2 
             prop.faceDirection = "vertical" 
             prop.unableDragAtMap = true
         }else if(prop.measureType == 'Hor MulDistance'){
-            prop.showDistances = true,  
-            prop.closed = false,
+            prop.showDistances = true,
+            prop.atPlane = true,
             prop.showEdges = true, 
             prop.minMarkers = 2 
             prop.faceDirection = "horizontal"  
         }else if(prop.measureType == 'Ver Distance'){
             prop.showDistances = true,  
-            prop.closed = false,
             prop.showEdges = true,
             prop.maxMarkers = 2,
             prop.minMarkers = 2,
             prop.faceDirection = "vertical" 
             prop.unableDragAtMap = true
         }else if(prop.measureType == 'Hor Distance'){
-            prop.showDistances = true,  
-            prop.closed = false,
+            prop.showDistances = true, 
             prop.showEdges = true,
             prop.maxMarkers = 2,
             prop.minMarkers = 2,
@@ -857,13 +851,13 @@ export class Measure extends ctrlPolygon{
                    
         }else if(prop.measureType == 'Area'){
             prop.showDistances = true,  
-            prop.showArea = true,  
+            prop.atPlane = true,                
             prop.showEdges = true,
             prop.closed = true, 
             prop.minMarkers = 3  
         }else if(prop.measureType == 'Hor Area'){
             prop.showDistances = true,  
-            prop.showArea = true,  
+            prop.atPlane = true,  
             prop.showEdges = true,
             prop.closed = true, 
             prop.minMarkers = 3  
@@ -871,7 +865,7 @@ export class Measure extends ctrlPolygon{
              
         }else if(prop.measureType == 'Ver Area'){
             prop.showDistances = true,  
-            prop.showArea = true,  
+            prop.atPlane = true,  
             prop.showEdges = true,
             prop.closed = true, 
             prop.minMarkers = 3 
@@ -879,14 +873,14 @@ export class Measure extends ctrlPolygon{
             prop.unableDragAtMap = true            
         }else if(prop.measureType == 'Rect Area'){
             prop.showDistances = true,  
-            prop.showArea = true,  
+            prop.atPlane = true,  
             prop.showEdges = true,
             prop.closed = true, 
             prop.minMarkers = 4 
             prop.maxMarkers = 4            
         }else if(prop.measureType == 'Hor Rect Area'){
             prop.showDistances = true,  
-            prop.showArea = true,  
+            prop.atPlane = true,  
             prop.showEdges = true,
             prop.closed = true, 
             prop.minMarkers = 4 
@@ -895,7 +889,7 @@ export class Measure extends ctrlPolygon{
             prop.faceDirection = "horizontal" 
         }else if(prop.measureType == 'Ver Rect Area'){
             prop.showDistances = true,  
-            prop.showArea = true,  
+            prop.atPlane = true,  
             prop.showEdges = true,
             prop.closed = true, 
             prop.minMarkers = 4 
@@ -904,6 +898,15 @@ export class Measure extends ctrlPolygon{
             prop.faceDirection = "vertical"  
             prop.unableDragAtMap = true
         } 
+        if(prop.atPlane && prop.closed){ //atPlane在同一平面上
+            prop.showArea = true
+        }
+        
+        
+        super.transformData(prop)
+        
+        
+        
     }
 
 

+ 1 - 27
src/custom/objects/tool/MeasuringTool.js

@@ -336,33 +336,7 @@ export class MeasuringTool extends THREE.EventDispatcher{
         
         
 		let domElement = this.viewer.renderer.domElement;
-
-		
-
-		const pick = (defaul, alternative) => {
-			if(defaul != null){
-				return defaul;
-			}else{
-				return alternative;
-			}
-		};
-
-		args.showDistances = (args.showDistances === null) ? true : args.showDistances;
-
-		args.showArea = pick(args.showArea, false);
-		args.showAngles = pick(args.showAngles, false);
-		args.showCoordinates = pick(args.showCoordinates, false);
-		args.showHeight = pick(args.showHeight, false);
-		args.showCircle = pick(args.showCircle, false);
-		args.showAzimuth = pick(args.showAzimuth, false);
-		args.showEdges = pick(args.showEdges, true);
-		args.closed = pick(args.closed, false);
-		args.maxMarkers = pick(args.maxMarkers, Infinity);
-        args.direction = args.direction//add
-		args.type = args.type    /*  || 'Measurement'; */
-        args.showGuideLine = pick(args.showGuideLine, false);  
-        args.isRect = pick(args.isRect, false);
-        
+ 
  
         let measure = new Measure(args);
         this.scene.add(measure);

+ 30 - 4
src/custom/objects/tool/ctrlPolygon.js

@@ -23,7 +23,7 @@ export class ctrlPolygon extends THREE.Object3D {
             this[i] = prop[i]
         }
         
-        if(this.showArea && this.dimension == '2d'){
+        if(this.atPlane && this.closed && this.dimension == '2d'){
             this.areaPlane = this.createAreaPlane(); 
             this.add(this.areaPlane)
         }
@@ -341,7 +341,7 @@ export class ctrlPolygon extends THREE.Object3D {
                 } */
                 this.getPoint2dInfo(points)
                 
-                var isIntersectSelf = this.showArea && !this.isRect && len > 3 && this.intersectSelf(this.point2dInfo.points2d)//检测相交
+                var isIntersectSelf = this.atPlane && !this.isRect && len > 3 && this.intersectSelf(this.point2dInfo.points2d)//检测相交
                 if(isIntersectSelf){
                     //not-allowed
                     viewer.dispatchEvent({
@@ -464,7 +464,7 @@ export class ctrlPolygon extends THREE.Object3D {
     };
     
     getFacePlane(){//最普通一种get方法,根据顶点。且假设所有点已经共面,且不重合
-        if(!this.showArea || this.points.length<3) return
+        if(!this.atPlane || this.points.length<3) return
         this.facePlane = new THREE.Plane().setFromCoplanarPoints(...this.points.slice(0,3) )
          
     }
@@ -680,7 +680,33 @@ export class ctrlPolygon extends THREE.Object3D {
         }
     }
     
-    transformData(){}
+    transformData(prop){
+        
+        
+        const pick = (defaul, alternative) => {
+			if(defaul != null){
+				return defaul;
+			}else{
+				return alternative;
+			}
+		};
+
+		prop.showDistances = (prop.showDistances === null) ? true : prop.showDistances; 
+		prop.showArea = pick(prop.showArea, false);
+		prop.showAngles = pick(prop.showAngles, false);
+		prop.showCoordinates = pick(prop.showCoordinates, false);
+		prop.showHeight = pick(prop.showHeight, false);
+		prop.showCircle = pick(prop.showCircle, false);
+		prop.showAzimuth = pick(prop.showAzimuth, false);
+		prop.showEdges = pick(prop.showEdges, true);
+		prop.closed = pick(prop.closed, false);
+		prop.maxMarkers = pick(prop.maxMarkers, Infinity);
+        prop.direction = prop.direction//add
+		prop.type = prop.type    
+        prop.showGuideLine = pick(prop.showGuideLine, false);  
+        prop.isRect = pick(prop.isRect, false);
+
+    }
     setSelected(){}
     
     

+ 1 - 0
src/custom/objects/tool/mapClipBox.js

@@ -24,6 +24,7 @@ export class mapClipBox extends ctrlPolygon {
         let prop = {
             points : getPoints(center, scale, 0),
             closed : true,
+            atPlane: true,
             isRect : true,
             dimension : '2d'
         }

+ 97 - 44
src/custom/potree.shim.js

@@ -626,7 +626,7 @@ Utils.datasetRotTransform = function(o={}){
     
 }
 
-Utils.isInsideFrustum = function(bounding, camera){// boundingBox在视野范围内有可见部分
+Utils.isInsideFrustum = function(bounding, camera){// bounding是否在视野范围内有可见部分(视野就是一个锥状box)
     let frustumMatrix = new THREE.Matrix4
     frustumMatrix.multiplyMatrices(camera.projectionMatrix, camera.matrixWorldInverse)
     
@@ -640,22 +640,52 @@ Utils.isInsideFrustum = function(bounding, camera){// boundingBox在视野范围
     }
 }
 
-Utils.isInsideBox = function(object,  boxMatrixInverse){//object可以是点或者bounding, box原为1*1*1,但可能形变
-    let frustum = new THREE.Frustum();
-    frustum.setFromProjectionMatrix(boxMatrixInverse) 
+Utils.isIntersectBox = function(object,  boxMatrix){//object是否有在box中的部分。 object可以是点或者bounding, box原为1*1*1,但可能形变
+    //let frustum = new THREE.Frustum();
+    //frustum.setFromProjectionMatrix(boxMatrixInverse) --错
+     
+    let px = new THREE.Vector3(+0.5, 0, 0).applyMatrix4(boxMatrix);
+    let nx = new THREE.Vector3(-0.5, 0, 0).applyMatrix4(boxMatrix);
+    let py = new THREE.Vector3(0, +0.5, 0).applyMatrix4(boxMatrix);
+    let ny = new THREE.Vector3(0, -0.5, 0).applyMatrix4(boxMatrix);
+    let pz = new THREE.Vector3(0, 0, +0.5).applyMatrix4(boxMatrix);
+    let nz = new THREE.Vector3(0, 0, -0.5).applyMatrix4(boxMatrix);
+
+    let pxN = new THREE.Vector3().subVectors(nx, px).normalize();
+    let nxN = pxN.clone().multiplyScalar(-1);
+    let pyN = new THREE.Vector3().subVectors(ny, py).normalize();
+    let nyN = pyN.clone().multiplyScalar(-1);
+    let pzN = new THREE.Vector3().subVectors(nz, pz).normalize();
+    let nzN = pzN.clone().multiplyScalar(-1);
+
+    let pxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pxN, px);
+    let nxPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nxN, nx);
+    let pyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pyN, py);
+    let nyPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nyN, ny);
+    let pzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(pzN, pz);
+    let nzPlane = new THREE.Plane().setFromNormalAndCoplanarPoint(nzN, nz);
+    let frustum = new THREE.Frustum(pxPlane, nxPlane, pyPlane, nyPlane, pzPlane, nzPlane);
+   
+    
+    
      
     if(object instanceof THREE.Box3){
-        return frustum.intersectsBox(object)  
-    }else if(object instanceof Array){//点合集,先求Sphere setFromPoints
+        var boxBound = new THREE.Box3(
+            new THREE.Vector3(-0.5,-0.5,-0.5), new THREE.Vector3(0.5,0.5,0.5),
+        ).applyMatrix4(boxMatrix)    //large boundingbox
+        if(!object.intersectsBox(boxBound))return
+        return frustum.intersectsBox(object)  //根据该函数, 若存在某个plane在box上的对应点都在plane背面,则不相交.  可得知在box构成的frustum倾斜时不准确,不相交也判断为相交,甚至不如bound相交准确。所以前面加步骤排除下,但仍不完全准确。(可在裁剪中将box放置到数据集上方旋转下校验)
+    }else if(object instanceof Array){//点合集, 只能粗略计算下
         let sphere = new THREE.Sphere()
         sphere.setFromPoints(object) 
-        return this.isInsideBox(sphere, boxMatrixInverse)
-
+        return this.isIntersectBox(sphere, boxMatrix) 
     }else if(object instanceof THREE.Sphere){
         return frustum.intersectsSphere(object)  
     }else if(object instanceof THREE.Vector3){
         return frustum.containsPoint(object)  
-    } 
+    }else if(object instanceof THREE.Matrix4){//第一个参数如果和第二个参数一样都是box的worldMatrix
+        
+    }
 
     /* containsPoint: ƒ containsPoint( point ) 
     intersectsBox: ƒ intersectsBox( box )
@@ -895,7 +925,11 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 	
 	let domWidth = areaSize.x; //renderer.domElement.clientWidth;
 	let domHeight = areaSize.y;//renderer.domElement.clientHeight;
-
+    let fov = (camera.fov * Math.PI) / 180;
+    let slope = Math.tan(fov / 2);
+    let projFactor0 = (0.5 * domHeight) / slope ;
+    
+    
 	// check if pointcloud has been transformed
 	// some code will only be executed if changes have been detected
 	if(!Potree._pointcloudTransformVersion){
@@ -957,12 +991,12 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 		//visible = visible || node.getLevel() <= 2;
 
 
-        let insideBox = (clipBox)=>{
+        let intersectBox = (clipBox)=>{
 
             let pcWorldInverse = pointcloud.matrixWorld.clone().invert();
-            let toPCObject = pcWorldInverse.multiply(clipBox.box.matrixWorld);
+            let toPCObject = pcWorldInverse.multiply(clipBox.box.matrixWorld);  //box乘上点云逆矩阵
 
-            let px = new THREE.Vector3(+0.5, 0, 0).applyMatrix4(pcWorldInverse);
+            /* let px = new THREE.Vector3(+0.5, 0, 0).applyMatrix4(pcWorldInverse);
             let nx = new THREE.Vector3(-0.5, 0, 0).applyMatrix4(pcWorldInverse);
             let py = new THREE.Vector3(0, +0.5, 0).applyMatrix4(pcWorldInverse);
             let ny = new THREE.Vector3(0, -0.5, 0).applyMatrix4(pcWorldInverse);
@@ -1003,7 +1037,12 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
             let intersects = frustum.intersectsBox(box); //node的bounding
 
              
-            return !!intersects
+            return !!intersects */
+            
+             
+            return Potree.Utils.isIntersectBox(box, pcWorldInverse) 
+            
+            
         }
 
         //改 总共两种box : 可见和不可见(都是并集)
@@ -1015,7 +1054,7 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
         let bigClipInBox = pointcloud.material.bigClipInBox
         
         if(visible && bigClipInBox){//不在剪裁下载的框内
-            if(!insideBox(bigClipInBox)){
+            if(!intersectBox(bigClipInBox)){
                 visible = false; 
             } 
         }
@@ -1024,7 +1063,7 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 		if(visible && clipBoxes_in.length > 0){//当有可见box时,需要在任一可见box内才可见
             let visi = false;
             for(let i = 0, length=clipBoxes_in.length; i < length; i++){ 
-                if(insideBox(clipBoxes_in[i])){
+                if(intersectBox(clipBoxes_in[i])){
                     visi = true;
                     break;
                 } 
@@ -1035,11 +1074,11 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
         }
         
         
-        //outside不做处理。因为node必须完全在clipBox内才能完全隐藏,而这里的intersect只能识别出部分在clipBox内
+        //outside不做处理。因为node必须完全在clipBox内才能完全隐藏,而这里的intersect只能识别出部分在clipBox内。因而只能说明不在任意一个box内绝对可见,没有意义,这里需要找出不可见的。
         /* if(visible && clipBoxes_out.length > 0){ //当有不可见box时,不在所有不可见box内才可见
             let visi = true;
             for(let i = 0,length=clipBoxes_out.length; i < length; i++){ 
-                if(insideBox(clipBoxes_out[i])){
+                if(intersectBox(clipBoxes_out[i])){
                     visi = false;
                     break;
                 } 
@@ -1127,7 +1166,7 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 			// }
 		}
 
-		// add child nodes to priorityQueue
+		// add child nodes to priorityQueue 由近及远、由大及小逐渐加载
 		let children = node.getChildren();
 		for (let i = 0; i < children.length; i++) {
 			let child = children[i];
@@ -1136,28 +1175,27 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 			if(camera.isPerspectiveCamera){
 				let sphere = child.getBoundingSphere();
 				let center = sphere.center;
-				//let distance = sphere.center.distanceTo(camObjPos);
-				
-				let dx = camObjPos.x - center.x;
-				let dy = camObjPos.y - center.y;
-				let dz = camObjPos.z - center.z;
-				
-				let dd = dx * dx + dy * dy + dz * dz;
-				let distance = Math.sqrt(dd);
-				
+				let dd = sphere.center.distanceToSquared(camObjPos);
+				  
+                let addPow = 0.25   //0-0.5 数字越大近处加载越快。但会造成远处加载慢甚至因pointBudge限制不加载 
+				let distance = Math.pow(dd,0.5+addPow)//Math.sqrt(dd); //提高距离权重,为了提高近处加载速度。   某些场景近处加载慢优化明显,如SS-t-cqCAL6rJ5i 
 				
+				//let attenuateDis = 10;//add
 				let radius = sphere.radius;
-                 
-				let fov = (camera.fov * Math.PI) / 180;
-				let slope = Math.tan(fov / 2);
-				let projFactor = (0.5 * domHeight) / (slope * distance);
+                  
+                let projFactor = projFactor0 / distance
 				let screenPixelRadius = radius * projFactor;
+                 
+                /* if(distance > attenuateDis){
+                    screenPixelRadius -= (distance - attenuateDis) * Math.sqrt(radius) * projFactor0 * 0.002
+                } */
+                
 				//screenPixelRadius 和 domHeight 成正比,所以手机横屏后screenPixelRadius会变小。这是正常的,因为vhov不变,相同物体高度在横屏后高度变小,所需要的密度不需要那么高了。但hfov横屏后扩大,所以可见的node范围变大,又增加了一些可见node;只是总体的可见node还是减少了。
 				//使用hfov和domWidth计算结果相同。
-                if(screenPixelRadius < pointcloud.minimumNodePixelSize){
+                if(screenPixelRadius < pointcloud.minimumNodePixelSize / Math.pow(dd,addPow)){
 					continue;
 				}
-			
+                //如果能得到该方向上的密度,也就是node数量,密度大的远处少加载,因为被遮挡了显示也没有意义,就好了。
 				weight = screenPixelRadius;
 
 				if(distance - radius < 0){
@@ -1189,7 +1227,11 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 	for (let i = 0; i < Math.min(Potree.maxNodesLoading, unloadedGeometry.length); i++) {
 		unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry); 
 	}
-
+    
+    //add:
+    Potree.numVisiblePoints = numVisiblePoints
+    
+    
 	return {
 		visibleNodes: visibleNodes,
 		numVisiblePoints: numVisiblePoints,
@@ -1198,10 +1240,20 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 };
 /* 
     note:
-    缓存中的点数 Potree.lru.numPoints 会 大于 每个点云显示的numVisiblePoints之和。
+    缓存中的点数 Potree.lru.numPoints 一般会 大于 每个点云显示点总数的numVisiblePoints 
     当超出缓冲区最大点云数时,加载的点云节点会被dispose彻底消除;否则,隐藏的节点就会等待再次被使用显示
-    要降低卡顿,就只需要降低Potree.pointBudget即可。为了level显示均匀,还能另外设置整体maxLevel
+    由于加载按照由近及远、由大及小的顺序,要降低卡顿,就只需要降低Potree.pointBudget即可。但目前只设置了三个层次;另外提供maxLevel细节调节,能显示更均匀. 最好多一个调节pointBudge的滑动条
+    
+    Potree.lru.numPoints      
+    Potree.numVisiblePoints  
+    viewer.scene.pointclouds[0].visibleNodes.length
  */
+ 
+ 
+ 
+ 
+ 
+ 
 {//HQSplatRenderer
     let oldInit = HQSplatRenderer.prototype.init;
     HQSplatRenderer.prototype.init = function(){
@@ -1605,11 +1657,11 @@ LRU.prototype.freeMemory = function(){
     if (this.elements <= 1) {
         return;
     } 
-    
+    let memoryRatio = browser.isMobile ? 2 : 3;
     //改成navvis的,使用pointBudget,否则四屏点云闪烁。 (似乎要比updateVisiblede的node时限制要宽些,作为缓存继续存着。否则会闪烁)
-    let max =  viewer.viewports.length * 2 * Potree.pointBudget// : 1000  // this.pageVisible ?  
+    let max =  viewer.viewports.length * memoryRatio * Potree.pointBudget 
        
-    for (; this.numPoints > max;  ) {//应该是从子node删除
+    for (; this.numPoints > max;  ) { 
         var node = this.getLRUItem();
         node && this.disposeDescendants(node); //this.disposeSubtree(node)
     } 
@@ -1636,7 +1688,7 @@ VolumeTool.prototype.startInsertion = function(args = {}){
     if(args.type){
         volume = new args.type();
     }else{
-        volume = new Potree.BoxVolume({clip:args.clip, clipTask:ClipTask.SHOW_OUTSIDE});
+        volume = new Potree.BoxVolume(args/* {clip:args.clip, clipTask:ClipTask.SHOW_OUTSIDE} */);
     }
       
     volume.name = args.name || 'Volume';
@@ -1662,13 +1714,13 @@ VolumeTool.prototype.startInsertion = function(args = {}){
         volume: volume
     });
     
-    if(viewer.scene.volumes.length>0){
+    /* if(viewer.scene.volumes.length>0){
         volume.rotation.copy(viewer.scene.volumes[viewer.scene.volumes.length-1].rotation); //使用上一个的旋转值
-    }
+    } */
     updateScale()
     this.viewer.scene.addVolume(volume);
     this.scene.add(volume);
-    viewer.transformObject(volume)
+    
     
     
     
@@ -1701,6 +1753,7 @@ VolumeTool.prototype.startInsertion = function(args = {}){
         volume.removeEventListener('drag', drag);
         volume.removeEventListener('drop', end);
         this.viewer.removeEventListener('cancel_insertions', cancel);
+        viewer.transformObject(volume)
     };
     
     volume.addEventListener('drag', drag);

+ 4 - 4
src/custom/settings.js

@@ -136,18 +136,18 @@ const config = {//配置参数   不可修改
             maxLevelPercent: 0.4, //最小为0
             percentByUser:true, //如果用户定义了percent,使用用户的
             pointBudget : browser.isMobile() ? 1*1000*1000 : 2*1000*1000, 
-            minNodeSize : browser.isMobile() ? 120 : 100 ,
+            minNodeSize : browser.isMobile() ? 80 : 40  ,
         }, 
         middle:{//balanced  //不同场景相同级别所产生的numVisibleNodes和numVisiblePoints不同,如果分层比较细,可能要到level8才能看清,那么level5看到的点就很大且很少,如隧道t-e2Kb2iU
             maxLevelPercent: 0.7,
             percentByUser:true,
-            pointBudget:browser.isMobile() ? 2*1000*1000 : 4*1000*1000, 
-            minNodeSize : browser.isMobile() ? 100 : 70 ,
+            pointBudget:browser.isMobile() ? 2*1000*1000 : 3.5*1000*1000, 
+            minNodeSize : browser.isMobile() ? 80 : 40  ,
         },
         high:{//highQuality
             maxLevelPercent: 1, 
             percentByUser:true,
-            pointBudget:browser.isMobile() ? 4*1000*1000 : 8*1000*1000,
+            pointBudget:browser.isMobile() ? 3*1000*1000 : 6*1000*1000,  //原本最高是8,但是大部分电脑都太卡了,降
             minNodeSize : browser.isMobile() ? 60 : 30 ,
         }
         //browser.isMobile() 时要不要限制下pointBudget,还是让用户自己调低质量?

+ 5 - 6
src/custom/viewer/ViewerNew.js

@@ -3567,12 +3567,11 @@ export class Viewer extends ViewerBase{
             
             
             
-             //试试改变位置,直视测量线。能避免倾斜角度造成的非常不居中、以及看不到面的情况 
-            if(object.facePlane/*  && window.focusMeasureFaceToIt */){
-                let normal
-                if(object.facePlane){
-                    normal = object.facePlane.normal.clone()
-                }               
+            //试试改变位置(方向),直视测量线。能避免倾斜角度造成的非常不居中、以及看不到面的情况 
+            if(object.points.length>2/*  && window.focusMeasureFaceToIt */){
+                
+                let facePlane = object.facePlane || new THREE.Plane().setFromCoplanarPoints(...object.points.slice(0,3) )
+                let normal = facePlane.normal.clone()                
                 let angle = this.scene.view.direction.angleTo(normal)
                 let minDiff = THREE.Math.degToRad(60) 
                 //console.log('angle',angle)

+ 1 - 1
src/navigation/FirstPersonControlsNew.js

@@ -451,7 +451,7 @@ export class FirstPersonControls extends THREE.EventDispatcher {
         }
         let prepareRotate = (e)=>{ 
             this.pointerDragStart = e.pointer.clone()
-            if(e.viewer.name == 'mapViewer' )return 
+            if(e.viewer.name != 'mainViewer' )return 
             let intersect = e.intersect || e.dragViewport.lastIntersect
             //在数据集外部时绕中心点旋转,在数据集内部时绕intersect点旋转(其他数据集的点也可以) 或者 原地旋转镜头
             let rotAroundPoint = Potree.settings.rotAroundPoint && e.dragViewport.camera.type != 'OrthographicCamera' &&  (viewer.atDatasets.length == 0 || intersect) && this.canMovePos(viewport) && !viewer.images360.isAtPano() && !this.viewer.inputHandler.pressedKeys[32]

+ 1 - 1
src/utils.js

@@ -212,7 +212,7 @@ export class Utils {
 		boundingBox.setFromPoints(vertices);
 
 		return boundingBox;
-	};
+	};//感觉就是bound.applyMatrix4(transform)
 
 	/**
 	 * add separators to large numbers

+ 10 - 5
src/utils/VolumeNew.js

@@ -30,14 +30,13 @@ export class Volume extends THREE.Object3D {
 	 
 		{ // event listeners
 			this.addEventListener('select', e => {
-                //console.log('select') 
-                this.selected = true
-                this.update() 
+                //console.log('select')
+                this.setSelected(true)   
+                
             });
 			this.addEventListener('deselect', e => {
                 //console.log('deselect') 
-                this.selected = false 
-                this.update()
+                this.setSelected(false)       
             });
             
             this.addEventListener('mouseover', e => {
@@ -54,6 +53,12 @@ export class Volume extends THREE.Object3D {
 
 	}
 
+    setSelected(state){//add
+        this.selected = !!state
+        this.update() 
+    }
+
+
 	get visible(){
 		return this._visible;
 	}

+ 1 - 1
src/viewer/sidebarNew.js

@@ -234,7 +234,7 @@ export class Sidebar{
         
         addBtn.on('click',()=>{
             
-            let volumeBox = this.volumeTool.startInsertion({clip: true});
+            let volumeBox = this.volumeTool.startInsertion({clip: true, clipTask:Potree.ClipTask.SHOW_OUTSIDE});
             
             
             let li = $("<li><button name='changeTask'>不可见</button><button name='chose'>选择</button><button name='delete'>删除</button></li>")