Ver código fonte

Merge branch '1standard' into 1fuse

# Conflicts:
#	src/custom/modules/panos/Panorama.js
#	src/custom/objects/tool/TransformControls.js
xzw 8 meses atrás
pai
commit
4f843850e6
39 arquivos alterados com 1065 adições e 666 exclusões
  1. 1 1
      libs/Cesium/Cesium.js
  2. 5 7
      libs/three.js/lines/LineMaterial.js
  3. 1 1
      libs/three.js/loaders/DRACOLoader.js
  4. 3 3
      libs/three.js/loaders/draco/draco_wasm_wrapper.js
  5. 121 1
      src/ExtendPointCloudOctree.js
  6. 1 3
      src/PointCloudOctree.js
  7. 3 2
      src/PotreeRendererNew.js
  8. 3 3
      src/custom/materials/BasicMaterial.js
  9. 4 1
      src/custom/materials/ModelTextureMaterial.js
  10. 4 1
      src/custom/mergeStartTest.js
  11. 14 9
      src/custom/modules/CameraAnimation/CamAniEditor.js
  12. 13 11
      src/custom/modules/CameraAnimation/CameraAnimation.js
  13. 37 26
      src/custom/modules/mergeModel/MergeEditor.js
  14. 21 6
      src/custom/modules/panos/Images360.js
  15. 15 11
      src/custom/modules/panos/Panorama.js
  16. 4 5
      src/custom/objects/Magnifier.js
  17. 109 67
      src/custom/objects/Monitor.js
  18. 6 3
      src/custom/objects/Overlay.js
  19. 4 2
      src/custom/objects/Tag.js
  20. 14 10
      src/custom/objects/TextSprite.js
  21. 29 12
      src/custom/objects/tool/Path.js
  22. 8 10
      src/custom/objects/tool/TransformControls.js
  23. 26 33
      src/custom/potree.shim.js
  24. 6 1
      src/custom/settings.js
  25. 57 6
      src/custom/start.js
  26. 492 395
      src/custom/three.shim.js
  27. 14 4
      src/custom/utils/Common.js
  28. 3 3
      src/custom/utils/CursorDeal.js
  29. 5 3
      src/custom/utils/History.js
  30. 3 0
      src/custom/utils/math.js
  31. 15 10
      src/custom/viewer/ViewerNew.js
  32. 2 1
      src/materials/shaders/depthBasic.fs
  33. 1 0
      src/navigation/InputHandlerNew.js
  34. 5 3
      src/navigation/OrbitControlsNew.js
  35. 2 2
      src/utils/VolumeNew.js
  36. 2 1
      src/viewer/EDLRendererNew.js
  37. 2 2
      src/viewer/ExtendScene.js
  38. 1 1
      src/viewer/ExtendView.js
  39. 9 6
      src/workers/BinaryDecoderWorker.js

Diferenças do arquivo suprimidas por serem muito extensas
+ 1 - 1
libs/Cesium/Cesium.js


+ 5 - 7
libs/three.js/lines/LineMaterial.js

@@ -543,13 +543,11 @@ ShaderLib[ 'line' ] = {
                     #endif 
                     
                     //vec4 diffuseColor = vec4(mix(diffuse, backColor_, mixFactor), opacity*(1.0 - clipFactor));
-                   
-                   
-                   
-                    diffuseColor = mix(diffuseColor, backColor_ , mixFactor);   
-                   
-                   
-                    diffuseColor.a *= (1.0 - clipFactor);  
+                    
+                    diffuseColor = mix(diffuseColor, backColor_ , mixFactor);  
+                    
+                    float r = pow(1.0 - clipFactor, 3.0); //更透明些  
+                    diffuseColor.a *= r;  
                 
                 #endif
             #endif

+ 1 - 1
libs/three.js/loaders/DRACOLoader.js

@@ -17,7 +17,7 @@ class DRACOLoader extends Loader {
 		super( manager );
 
 		this.decoderPath = '';
-		this.decoderConfig = {};
+		this.decoderConfig = {TOTAL_MEMORY:Potree.settings.TOTAL_MEMORY};
 		this.decoderBinary = null;
 		this.decoderPending = null;
 

Diferenças do arquivo suprimidas por serem muito extensas
+ 3 - 3
libs/three.js/loaders/draco/draco_wasm_wrapper.js


+ 121 - 1
src/ExtendPointCloudOctree.js

@@ -3,10 +3,13 @@ import * as THREE from "../libs/three.js/build/three.module.js";
  
 import {ExtendPointCloudMaterial} from "./materials/ExtendPointCloudMaterial.js";
  
-import {PointCloudOctree} from './PointCloudOctree.js'
+import {PointCloudOctree,  PointCloudOctreeNode} from './PointCloudOctree.js'
 import {PointSizeType } from "./defines.js";
 import math from './custom/utils/math.js'
 
+
+
+ 
 export class ExtendPointCloudOctree extends PointCloudOctree{
     constructor(geometry, material){
         material = material || new ExtendPointCloudMaterial();
@@ -785,4 +788,121 @@ export class ExtendPointCloudOctree extends PointCloudOctree{
     
     
     
+    deepestNodeAt(position){ //改
+		let startTime = performance.now()
+		const toObjectSpace = this.matrixWorld.clone().invert();
+
+		const objPos = position.clone().applyMatrix4(toObjectSpace);
+
+		let current = this.root;
+		while(true){
+
+			let containingChild = null;
+            
+			for(const child of current.children){ 
+				if(child !== undefined && !containingChild){//
+					if(child.getBoundingBox().containsPoint(objPos)){
+						containingChild = child;
+					}
+				}
+			}
+
+			if(containingChild !== null && containingChild instanceof PointCloudOctreeNode){//如果是PointCloudOctreeGeometryNode可能geometry还没加载
+				current = containingChild;
+			}else{
+				break;
+			}
+		}
+
+		const deepest = current;
+        console.log('deepestNodeAt',  performance.now() - startTime  )
+		return deepest;
+	}
+    
+    
+    getNearestPoint(position, onlySearchLeaves){//add 输入一个世界坐标,查找该点云中和它最近的点
+        let startTime = performance.now()
+        let inNode = this.deepestNodeAt(position)
+        
+        const toObjectSpace = this.matrixWorld.clone().invert();
+		const objPos = position.clone().applyMatrix4(toObjectSpace);    //该值记录一下,以后不改两点云相对位置直接用      
+        let firstNode = inNode || this.root  //第一个搜寻点的node为所在node,初步找出最近点
+        
+        let nearest = firstNode.searchNearestPoint(position, {point:null, disSquare:Infinity})
+        nearest.inNode = inNode?.name
+        
+        //重新回到根结点向下找邻近node 
+        let traverse = (current)=>{
+            if(current == firstNode || current.getBoundingBox().distanceToPoint(objPos) < nearest.dis){ 
+                onlySearchLeaves || current.searchNearestPoint(position, nearest) //搜寻当前节点
+                let children = current.children.filter(e=>e && e instanceof PointCloudOctreeNode)
+                if(children.length){
+                    for(const child of children){ 
+                        if(child != firstNode){  
+                            traverse(child)
+                        } 
+                    }
+                }else{
+                    onlySearchLeaves && current.searchNearestPoint(position, nearest) //搜寻叶子节点
+                }
+            }
+            
+        }
+        traverse(this.root) 
+        console.log('getNearestPoint',  nearest,   performance.now() - startTime  )
+    }
+    
+    
+    
+    
 }
+
+
+ 
+PointCloudOctreeNode.prototype.searchNearestPoint = function(pos, nearest = {point:null,disSquare:Infinity}){
+    let positions = this.geometryNode.geometry.attributes.position
+    let tempPos = new THREE.Vector3
+    
+    const toObjectSpace = this.sceneNode.matrixWorld.clone().invert();
+    const objPos = pos.clone().applyMatrix4(toObjectSpace); 
+    let startTime = performance.now(), finded
+   
+    for(let i=0;i<positions.count;i++){
+        tempPos.fromArray(positions.array.slice(i*3,i*3+3))
+        
+        //let diff = new THREE.Vector3().subVectors(tempPos,objPos)
+        if(nearest.dis != void 0 && !Potree.math.closeTo(tempPos,objPos, nearest.dis)){//先筛除在xyz方向上的距离
+            continue;
+        }
+        let d = tempPos.distanceToSquared(objPos)
+        if(d<nearest.disSquare){
+            finded = true, nearest.point = tempPos, nearest.disSquare=d
+            nearest.dis == void 0 && (nearest.dis = Math.sqrt(nearest.disSquare)) //update
+        }
+    }
+    if(finded){
+        nearest.dis = Math.sqrt(nearest.disSquare) //update
+        nearest.point = tempPos.applyMatrix4(this.sceneNode.matrixWorld) //global pos
+        nearest.nodeName = this.name
+    }
+    console.log('node searchNearestPoint',  this.name,  performance.now() - startTime )
+    //onlySearchLeaves开启后减少了10倍时间,但小概率不准,误差:    点云上的坐标 0.05m , 非点云上的0.1m
+    return nearest 
+}
+
+/* 
+
+
+搜索方A pointLoaded
+    let tempPos = new THREE.Vector3
+    let newAttri = ...
+    for(let i=0;i<positions.count;i++){
+        tempPos.set(positions[i*3], positions[i*3+1],positions[i*3+2]) 
+        tempPos.applyMatrix4(this.matrixWorld)
+        cloudB.getNearestPoint(tempPos)
+    }
+
+
+
+
+ */

+ 1 - 3
src/PointCloudOctree.js

@@ -206,9 +206,7 @@ export class PointCloudOctree extends PointCloudTree {//base
 	toTreeNode (geometryNode, parent) {
 		let node = new PointCloudOctreeNode();
 
-		// if(geometryNode.name === "r40206"){
-		//	console.log("creating node for r40206");
-		// }
+		 
 		let sceneNode = new THREE.Points(geometryNode.geometry, this.material);
 		sceneNode.name = geometryNode.name;
 		sceneNode.position.copy(geometryNode.boundingBox.min);

+ 3 - 2
src/PotreeRendererNew.js

@@ -1803,8 +1803,9 @@ export class Renderer {
 		// RENDER
         
         let mat = params.material || traversalResult.octrees[0].material
-         
-        if(Potree.settings.cloudSameMat && viewer.scene.volumes.length == 0 && mat.pointSizeType != PointSizeType.ADAPTIVE && mat.activeAttributeName != "level of detail"){
+        let cloudSameMat = Potree.settings.cloudSameMat && !traversalResult.octrees.some(e=>e.material.activeAttributeName != mat.activeAttributeName) //activeAttributeName都一样才行
+           
+        if(cloudSameMat && viewer.scene.volumes.length == 0 && mat.pointSizeType != PointSizeType.ADAPTIVE && mat.activeAttributeName != "level of detail"){
             this.renderOctree(traversalResult.octrees, null, camera, target, params);  //所有点云除了个别属性需要在shader中更新,其他都使用第一个点云的材质
         }else for (const octree of traversalResult.octrees) {  
             for (const octree of traversalResult.octrees) { 

+ 3 - 3
src/custom/materials/BasicMaterial.js

@@ -15,14 +15,14 @@ class BasicMaterial  extends THREE.ShaderMaterial{
             uniforms:{
                 color:  {type:'v3',   value: color} ,
                 map:    {type: 't',    value: o.map },
-                opacity : {type:'f',    value : 1}
+                opacity : {type:'f',    value : o.opacity == void 0 ? 1 : o.opacity  }
                  
             },
             vertexShader: Shaders['basicTextured.vs'],   
             fragmentShader: Shaders['basicTextured.fs'], 
             defines:{HasColor:'' }
         },o))
-        this.opacity = o.opacity == void 0 ? 1 : o.opacity 
+        //this.opacity = o.opacity == void 0 ? 1 : o.opacity 
     } 
      
     
@@ -38,7 +38,7 @@ class BasicMaterial  extends THREE.ShaderMaterial{
     
     set opacity(o){
         this.uniforms && (this.uniforms.opacity.value = o)
-        this.transparent = o<1
+        //this.transparent = o<1
     }
     get opacity(){
         return this.uniforms.opacity.value  

+ 4 - 1
src/custom/materials/ModelTextureMaterial.js

@@ -463,7 +463,10 @@ export default class ModelTextureMaterial extends THREE.RawShaderMaterial {
             defines.UnableMixTwoDepth = 1  //该系统在开启硬件加速后,webgl容易出bug。如过渡时黑屏报错,因无法将两个depth叠加。见bug记录
         }  
         let {vs,fs} = Common.changeShaderToWebgl2(shader.vertexShader, shader.fragmentShader, 'RawShaderMaterial')
-        
+        if(!Potree.settings.isWebgl2){
+            defines['round(x)'] = 'floor(x + 0.5)'   //webgl1 unsupport round
+            fs = fs.replace('int(round(color.g * 255.0)) << 8', 'int(round(color.g * 255.0 * pow(2.0, 8.0)))')  //unsupport <<
+        }
         super({
             fragmentShader: fs,
 			vertexShader: vs,

+ 4 - 1
src/custom/mergeStartTest.js

@@ -354,8 +354,11 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
     ], tileIndex = 0
     
      let glbUrls = [ 
+     
+        {url:`${Potree.resourcePath}/models/glb/animation/kid.glb`, angle:Math.PI/2},
+     
         {url:`${Potree.resourcePath}/models/glb/animation/Soldier.glb`, angle:Math.PI/2},
-        {url:`${Potree.resourcePath}/models/glb/animation/man.glb`, angle:Math.PI/2}, /* 
+        {url:`${Potree.resourcePath}/models/glb/animation/man.glb`, angle:0}, /* 
         {url:`${Potree.resourcePath}/models/glb/animation/man--running.glb`, angle:Math.PI/2},
         {url:`${Potree.resourcePath}/models/glb/animation/man--walk.glb`, angle:Math.PI/2}, */
         {url:`${Potree.resourcePath}/models/glb/animation/dog.glb`, angle:Math.PI/2},

+ 14 - 9
src/custom/modules/CameraAnimation/CamAniEditor.js

@@ -99,13 +99,13 @@ let CamAniEditor = {
         
         
         let currentPlay 
-        let emitIndex = (indexInAni=0)=>{
+        let emitIndex = (indexInAni=0)=>{//更新当前飞到的index
             let ani = sections[currentPlay] 
             let currentIndex = 0
             if(ani instanceof CameraAnimation){
                 currentIndex = ani.originIndexStart + indexInAni
             }else{
-                currentIndex = Math.max(0, data.points.indexOf(ani) - 1)
+                currentIndex = Math.max(0, data.points.indexOf(ani) /* - 1 */) //因为是开始飞,还没飞到所以-1
             }
             event_.dispatchEvent({type:'updateCurrentIndex', currentIndex  })    
         }
@@ -119,10 +119,10 @@ let CamAniEditor = {
                     if(index == sections.length){
                         return event_.dispatchEvent('playDone')
                     }
-                    
+                    console.log('playNext',index)
                     let ani = sections[index]
                     currentPlay = index 
-                    emitIndex()
+                    
                     
                     if(ani instanceof CameraAnimation){
                         Potree.settings.displayMode = 'showPointCloud'
@@ -143,29 +143,34 @@ let CamAniEditor = {
                         }else{
                             duration = 600 //起始
                         }
+                        
+                        
                         viewer.images360.flyToPano({pano, quaternion, duration, callback:()=>{
-                            
+                             
+                            emitIndex()
                             let next = ()=>{
                                 let stayTime = (!sections[index-1] || sections[index-1] instanceof CameraAnimation) && sections[index+1] && sections[index+1] instanceof CameraAnimation ? 1000 : 300  //前后都是点云模式的话停留久一点。最好在页面上能设置
-                                console.log('stayTime',stayTime)
+                                //console.log('stayTime',stayTime)
                                 setTimeout(()=>{
                                     currentPlay != void 0 && playNext(index + 1)
                                 },stayTime) //稍作停留,不然点云-全景-点云的话根本看不到全景
                             }
                             if(/* ani.displayMode == 'showPanos' &&  */Potree.settings.displayMode != 'showPanos'){//刚加载完就飞走吗?
+                                
                                 Potree.settings.displayMode = 'showPanos'
                                 viewer.images360.addEventListener('endChangeMode',()=>{
+                                    console.log(2)
                                     next()
                                 },{once:true})  
-                            }else{
+                            }else{ 
                                 next()
                             }
                             //
-                        }}) 
+                        },retryUntilArrive:true}) 
                     }
                 }
                 playNext(0)
-                
+                emitIndex() //0
            
             },
             

+ 13 - 11
src/custom/modules/CameraAnimation/CameraAnimation.js

@@ -399,12 +399,13 @@ export class CameraAnimation extends THREE.EventDispatcher{
 		
 	 
          
-        let position = this.posCurve.getPointAt(percent); // 需要this.posCurve.points.length>1 否则报错
-        let quaternion  
+        
+        let quaternion, position  
         if(this.quaFromCurveTan){//沿着curve行走,目视curve前方
+            position = this.posCurve.getPointAt(percent);
             let percent2 = percent + (this.tangentDt || 0.001)
             if(percent2 <= 1){
-                let position2 = this.posCurve.getPointAt(percent2);
+                let position2 = this.posCurve.getPointAt(percent2); 
                 quaternion = math.getQuaFromPosAim( position,  position2) 
             }else{
                 quaternion = lastQuaternion
@@ -418,23 +419,24 @@ export class CameraAnimation extends THREE.EventDispatcher{
                 let curIndexPercent = this.newPointsPercents[this.currentIndex];
                 let nextIndexPercent = this.newPointsPercents[this.currentIndex+1];
                 let progress = (percent - curIndexPercent) / (nextIndexPercent - curIndexPercent)//在这两个节点间的百分比
-                
-                //投影到原本的 posCurve.pointsPercent上:
-                let curIndexOriPercent = this.posCurve.pointsPercent[this.currentIndex] 
-                let nextIndexOriPercent = this.posCurve.pointsPercent[this.currentIndex+1] 
-                percent = curIndexOriPercent + (nextIndexOriPercent - curIndexOriPercent) * progress
-                
+                 
                 let endQuaternion = this.quaternions[this.currentIndex+1]
                 let startQuaternion = this.quaternions[this.currentIndex]       
                 quaternion = (new THREE.Quaternion()).copy(startQuaternion) 
                 lerp.quaternion(quaternion, endQuaternion)(progress) 
                 
+                
+                //投影到原本的 posCurve.pointsPercent上:
+                let curIndexOriPercent = this.posCurve.pointsPercent[this.currentIndex] 
+                let nextIndexOriPercent = this.posCurve.pointsPercent[this.currentIndex+1] 
+                percent = curIndexOriPercent + (nextIndexOriPercent - curIndexOriPercent) * progress
                 /* if(this.posInterpolate){  
                     let endPos = this.posCurve.points[this.currentIndex+1]
                     let startPos = this.posCurve.points[this.currentIndex]       
                     position = (new THREE.Vector3()).copy(startPos) 
                     lerp.vector(position, endPos)(progress) 
-                }           */      
+                }           */ 
+                position = this.posCurve.getPointAt(percent); // 需要this.posCurve.points.length>1 否则报错                
             }else{ 
                 this.currentIndex = this.posCurve.points.length - 1;
                 quaternion = this.quaternions[this.currentIndex]
@@ -579,7 +581,7 @@ export class CameraAnimation extends THREE.EventDispatcher{
             
             if(currentIndex != this.currentIndex){
                 currentIndex = this.currentIndex
-                //console.log('updateCurrentIndex', currentIndex)
+                console.log('updateCurrentIndex', currentIndex)
                 this.dispatchEvent({type:'updateCurrentIndex', currentIndex  })
             }
             

+ 37 - 26
src/custom/modules/mergeModel/MergeEditor.js

@@ -12,7 +12,7 @@ import Compass from "../../objects/tool/Compass.js";
 import {TransformControls} from "../../objects/tool/TransformControls.js";
 import History from "../../utils/History.js"
 import {Box3Helper} from "../../../utils/Box3Helper.js";
- 
+import {BoxVolume} from '../../../utils/VolumeNew.js'
 import {TextSprite} from '../../objects/TextSprite.js' 
   
  
@@ -58,12 +58,19 @@ let MergeEditor = {
     
     SplitScreen : new SplitScreen(),
     
-    init(){  
-    
+    init(){   
         this.boxHelper = new Box3Helper(new THREE.Box3(new THREE.Vector3(-0.5,-0.5,-0.5), new THREE.Vector3(0.5,0.5,0.5)));
         viewer.scene.scene.add(this.boxHelper)
         Potree.Utils.updateVisible(this.boxHelper,'unselect',false)
+        this.boxHelper.material.opacity = 0.8;
+        
+        let boxHelper2 = new Box3Helper(new THREE.Box3(new THREE.Vector3(-0.5,-0.5,-0.5), new THREE.Vector3(0.5,0.5,0.5)));
+        boxHelper2.material.opacity = 0.2; boxHelper2.material.transparent = true, boxHelper2.material.depthTest = false; 
+        this.boxHelper.add(boxHelper2) //透明一点的boxHelper */
+        
         
+         
+         
         this.lastMemoryState = {}
         
     
@@ -73,19 +80,19 @@ let MergeEditor = {
                     data = Potree.Common.CloneObject(data) //避免使用后更改数据又被使用 
                     let matrix = data.object.parent ? data.object.parent.matrixWorld.clone().invert().multiply(data.matrixWorld) : data.matrixWorld
                     matrix.decompose( data.object.position, data.object.quaternion, data.object.scale );
-                    data.object.boundCenter.copy(data.boundCenter)
                     data.object.dispatchEvent('changeByHistory') 
-                    data.object.dispatchEvent('transformChanged')                    
+                    data.object.dispatchEvent('transformChanged')  
+                    this.getBoundCenter(data.object)    
                     viewer.dispatchEvent('content_changed')
+                    
                     //回退到上一次编辑的全局位置
                     return true
                 }  
             },
-            getData:(object)=>{   
+            getData:(object)=>{    
                 return {
                     object,
-                    matrixWorld:  object.matrixWorld.clone(),
-                    boundCenter: object.boundCenter.clone()
+                    matrixWorld:  object.matrixWorld.clone() 
                 }
             } 
         })  
@@ -122,7 +129,8 @@ let MergeEditor = {
             
             this.transformControls = new TransformControls(viewer.mainViewport.camera, viewer.renderArea,{
                 //dontHideWhenFaceCamera: true,
-                showRotXYZE : true
+                showRotXYZE : true,
+                minScale: new THREE.Vector3(0.00001,0.00001,0.00001)
             });
             //this.transformControls.space = 'local'//为了在当前方向上平移
             this.transformControls.setSize(1.5)
@@ -202,7 +210,7 @@ let MergeEditor = {
                     this.selectModel(object, posInModel) 
                 }else{
                     //if(!viewer.inputHandler.selection[0]){//正在平移和旋转,不允许取消
-                      if(this.selected == object && this.transformControls.mode == 'translate'){
+                      if(this.selected == object && this.transformControls.object == object && this.transformControls.mode == 'translate'){
                           this.selectModel(object, posInModel)  //update click pos
                       }else{
                           this.selectModel(null)
@@ -394,10 +402,10 @@ let MergeEditor = {
         Potree.Utils.setObjectLayers(this.transformControls, 'layer1' ) 
         this.transformControls.view = viewer.viewports[0].view
         this.transformControls.camera = viewer.viewports[0].camera
-        this.transformControls._gizmo.hideAxis = {translate:['z'], rotate:['x','y','z'] }
+        this.transformControls._gizmo.hideAxis = {translate:['z'], rotate:['x','y','z'],  scale:['x','y','z' ] }
         this.transformControls2.view = viewer.viewports[1].view
         this.transformControls2.camera = viewer.viewports[1].camera
-        this.transformControls2._gizmo.hideAxis = {translate:['x','y'], rotate:['x','y','z'] }
+        this.transformControls2._gizmo.hideAxis = {translate:['x','y'], rotate:['x','y','z'], scale:['x','y','z' ] }
         
 
         this.secondCompass.changeViewport(viewer.viewports[0])
@@ -423,7 +431,7 @@ let MergeEditor = {
         } */
         this.transformControls.camera = viewer.viewports[0].camera
         this.transformControls.view = viewer.viewports[0].view 
-        this.transformControls._gizmo.hideAxis = {rotate:['e']}
+        this.transformControls._gizmo.hideAxis = {rotate:['e'], scale:['x','y','z' ]}
         Potree.Utils.setObjectLayers(this.transformControls, 'sceneObjects' )  //恢复
         
         
@@ -479,6 +487,7 @@ let MergeEditor = {
                 this.updateMemoryUsage()
             },{once:true})  
         }) */
+        this.getBoundCenter(model) //保险起见加一下
         let weightUpdate = ()=>{
             this.changeModelPointCount(model,'add') 
             this.updateMemoryUsage()
@@ -534,7 +543,7 @@ let MergeEditor = {
         this.updateMemoryUsage()
     },
     
-    selectModel(model, state=true, fitBound, by2d){
+    selectModel(model, state=true, focus, by2d){
         if(!model) {
             model = this.selected
             state = false
@@ -547,13 +556,13 @@ let MergeEditor = {
                 if(this.selected == model) return
                 else{
                     let transToolAttached = !!this.transformControls.object
-                    this.selectModel(this.selected, false, fitBound, by2d)
+                    this.selectModel(this.selected, false, focus/* , by2d */)
                     transToolAttached && this.transformControls.attach(model)
                 }
             }
             this.selected = model
              
-            MergeEditor.focusOn(model, 500, !!fitBound)     //通过在场景里点击模型的话,不focus
+            MergeEditor.focusOn(model, 500, !!focus)     //通过在场景里点击模型的话,不focus
               
            
             this.showModelOutline(model)
@@ -639,20 +648,22 @@ let MergeEditor = {
             viewer.outlinePass.edgeStrength = edgeStrengths.glb
         }  
     },*/ 
-    focusOn(objects, duration = 400, fitBound=true, dontLookUp, dir){  
+    focusOn(objects, duration = 400, focus=true, dontLookUp, dir){  
         if(!(objects instanceof Array)){
             objects = [objects]
         }
+        let points = [] //用points会更近一些准一点
         let boundingBox = new THREE.Box3
         objects.forEach(object=>{
-            boundingBox.union(object.boundingBox.clone().applyMatrix4(object.matrixWorld))
+            points.push(...Common.getBoundPoints(object.boundingBox, object.matrixWorld)) 
+            boundingBox.union(object.bound/* object.boundingBox.clone().applyMatrix4(object.matrixWorld) */)
         })
         
         let len = boundingBox.getSize(new THREE.Vector3).length()
         Potree.settings.cameraFar = Math.max( Potree.settings.cameraFar, len*3 )
         
-        if(fitBound){
-            viewer.focusOnObject({boundingBox}, 'boundingBox', duration, {dontLookUp, dontChangeCamDir:dir?false:true, dir}) 
+        if(focus){          
+            viewer.focusOnObject({boundingBox, points }, 'boundingBox', duration, {boundScale: 0.8, dontLookUp, dontChangeCamDir:dir?false:true, dir}) //boundScale小一点离近一点
         }else{ 
         
             /* 
@@ -786,7 +797,7 @@ let MergeEditor = {
             model.rotateMatrix = new THREE.Matrix4().makeRotationFromEuler(model.rotation).multiply(model.rot1MatrixInvert);   
             model.transformMatrix.multiplyMatrices(model.matrix, model.posRot1MatrixInvert)   
             model.panos.forEach(e=>e.transformByPointcloud())
-            model.bound = model.boundingBox.clone().applyMatrix4(model.matrixWorld)
+            //model.bound = model.boundingBox.clone().applyMatrix4(model.matrixWorld)
         } 
         if(model.panos){
             model.transformInvMatrix.copy(model.transformMatrix).invert()  
@@ -864,26 +875,26 @@ let MergeEditor = {
             occlusionDistance: 0.9,//变为backColor距离 
             maxOcclusionFactor:0.7,
             maxClipFactor:1,
-            text:model.name, sizeInfo:{width2d:150},
+            text:model.name, sizeInfo:{width2d:200},
             rectBorderThick:1,            
             borderColor:{r:200,g:200,b:200,a:0.5}, 
             textColor:{r:255 ,g:255,b:255,a:1.0}, 
-            textshadowColor:'black',
-            backgroundColor:{r: 100,g:100,b:100,a:0.3},
+            //textshadowColor:'black',
+            backgroundColor:{r: 0,g:0,b:0,a:0.3},
             borderRadius: 6,   
             fontsize: 20,  fontWeight:'',//thick
             renderOrder : Potree.config.renderOrders.tag.label, 
             pickOrder: Potree.config.renderOrders.tag.label,
             useDepth : true ,
             maxLineWidth: 300,
-            transform2Dpercent:{x:0,y:1.3}, //向上移动 
+            transform2Dpercent:{x:0,y:0.5}, //向上移动一半 
             textAlign: Potree.settings.isOfficial && 'left'
         }) 
         model.titleLabel = titleLabel
         viewer.scene.scene.add(titleLabel)
         let updatePos = ()=>{
             titleLabel.position.copy(model.boundCenter)  
-            titleLabel.position.z += model.boundSize.z / 2          //暂时加载模型顶部,但也可能如果旋转了要在头顶
+            titleLabel.position.z += model.boundSize.z * 0.55   //暂时加载模型顶部,但也可能如果旋转了要在头顶
             titleLabel.updatePose()
         }
         let setVisible = ()=>{

+ 21 - 6
src/custom/modules/panos/Images360.js

@@ -179,6 +179,7 @@ export class Images360 extends THREE.EventDispatcher{
               /*  || Potree.settings.editType == 'pano' && viewer.modules.PanoEditor.entered */
                //||   Potree.settings.editType == 'merge' && !e.intersectPoint || viewer.inputHandler.hoveredElements[0] && viewer.inputHandler.hoveredElements[0].isModel && e.intersectPoint.distance > viewer.inputHandler.hoveredElements[0].distance
                || Potree.settings.editType == 'merge' && !Potree.settings.mergeType2
+               || Potree.settings.editType == 'merge' && (e.intersect?.object && !e.intersect.object.is4dkkModel) //支持全景模式下点击非场景模型
                //|| Potree.settings.mergeType2 && Potree.settings.displayMode == 'showPointCloud' 
             )  return 
              
@@ -260,7 +261,7 @@ export class Images360 extends THREE.EventDispatcher{
                             btnHot.on('click',()=>{
                                  onHot = !onHot    
                                  Potree.settings.showHotIr = onHot
-                                 btnHot.text((btnHot?'关闭':'打开')   +  '热成像')
+                                 btnHot.text((onHot?'关闭':'打开')   +  '热成像')
                             })
                         }
                         if(attrs.temp){
@@ -287,7 +288,7 @@ export class Images360 extends THREE.EventDispatcher{
                     },100)
                     
                                          
-                })
+                },{once:true})
                 
                 
             }
@@ -784,6 +785,7 @@ export class Images360 extends THREE.EventDispatcher{
     judgeModelMat(object/* , isCurModel */){
         if(!(Potree.settings.mergeType2 && Potree.settings.modelSkybox))return
         object.traverse(mesh=>{
+            if(mesh.isMonitor)return {stopContinue:true}
             if(mesh.material){
                 if(!mesh.materialOutside){
                     mesh.materialOutside = mesh.material
@@ -924,6 +926,17 @@ export class Images360 extends THREE.EventDispatcher{
                 this.cancelFlyToPano(toPano)
                 this.updateClosestPano(this.closestPano,false) //飞行结束后取消点击漫游点时得到的closestPano
             }else{ 
+                if(toPano.retryUntilArrive){//一直试直到可以飞成功
+                    //console.log('wait for reFly to pano ', toPano.pano.id)
+                    let retry = (e)=>{//重飞
+                        if(e.makeIt){
+                            this.removeEventListener('flyToPanoDone', retry) 
+                            //console.log('reFly to pano ', toPano.pano.id)
+                            this.flyToPano(toPano) 
+                        }
+                    }
+                    this.addEventListener('flyToPanoDone', retry)  
+                }
             }
             
             this.dispatchEvent({type:'flyToPanoDone', makeIt, disturb})
@@ -932,22 +945,24 @@ export class Images360 extends THREE.EventDispatcher{
         }
         
         if(!toPano.pano.enabled)return done(false,true);
-        //Potree.Log('hope flyToPano: '+toPano.pano.id, toPano.pano.position.toArray() )
+        //Potree.Log('hope flyToPano: '+toPano.pano.id/* , toPano.pano.position.toArray()  */)
         
         
          
         
         if(!toPano.canCancelLast && this.latestToPano && this.latestToPano != toPano && (//还在飞
             this.latestToPano.pano != this.currentPano || !this.isAtPano())){//如果旧的toPano只在pano旋转镜头,就直接取消旧的,继续执行 
+            //console.log('还在飞', this.latestToPano.pano.id)
             return done(false) 
         } 
          
         if(this.currentPano == toPano.pano && this.isAtPano() && !toPano.target && !toPano.quaternion  ){
             //已在该pano
+            //console.log('已在该pano', this.currentPano.id)
             this.dispatchEvent({type:'flyToPano', toPano})
             return done(true);
         }
-        //Potree.Log('flyToPano: '+toPano.pano.id, toPano.pano.position.toArray()  /* this.latestToPano && this.latestToPano.pano.id */ )
+        //Potree.Log('flyToPano: '+toPano.pano.id /*, toPano.pano.position.toArray()  this.latestToPano && this.latestToPano.pano.id */ )
          
         
         
@@ -2143,7 +2158,7 @@ export class Images360 extends THREE.EventDispatcher{
                     let cos = dir.dot(vec2)  
                     //let result = (- dis1  - Math.pow(dis2 , 1.5)) / (cos + 2)  // cos+2是为了调整到1-3, 
                     
-                    let result =  (dis1 + dis2*0.3) * ( -1 + cos*0.9 ) //尽量贴近最佳位置的角度, 或贴近相机原来的角度 。尽量靠近最佳观测点,并且优先选择靠近目标点的位置.(注意cos的乘数不能太接近1,否则容易只考虑角度)
+                    let result =  (dis1 + dis2*0.3) * ( -1 + cos*0.4 ) //尽量贴近最佳位置的角度, 或贴近相机原来的角度 。尽量靠近最佳观测点,并且优先选择靠近目标点的位置.(注意cos的乘数不能太接近1,否则容易只考虑角度)
                     //Potree.Log(pano.id, dis1, dis2,  cos,  result,{font:{toFixed:2,fontSize:10}}) 
                      
                     return  result
@@ -2773,7 +2788,7 @@ Images360.prototype.checkAndWaitForPanoLoad = function() {
         
         let changeMode = (e)=>{
             if(e.mode == 'showPointCloud'){
-                console.warn('切到点云模式了,就删除loadedCallback记录',pano.id)//否则再次转为showPanos会被withinTime阻拦
+                //console.warn('切到点云模式了,就删除loadedCallback记录',pano.id)//否则再次转为showPanos会被withinTime阻拦
                 delete loadingPanos[pano.id] 
                 viewer.cancelLoad(pano)
                 

+ 15 - 11
src/custom/modules/panos/Panorama.js

@@ -300,8 +300,8 @@ class Panorama extends THREE.EventDispatcher{
         if(!this['has_'+type] || this[type+'Tex'] || this[type+'Loading'])return
         
          
-        let url = `${Potree.settings.urls.prefix1}/testdata/${Potree.settings.number}/data/${this.pointcloud.sceneCode}/imagemap/${this.originID}_${type}.png`
-        //let url = `${Potree.settings.urls.prefix1}/testdata/${Potree.settings.number}/data/${this.pointcloud.sceneCode}/imagemap/${this.originID}_temp.png`
+        let url = this.pointcloud.typesUrl + `${this.originID}_${type}.png`
+        //let url = `${Potree.settings.urls.prefix1}/testdata/${this.pointcloud.sceneCode}/data/${this.pointcloud.sceneCode}/imagemap/${this.originID}_temp.png`
          
         let range = {min:Infinity, max:-Infinity, minPixel:null, maxPixel:null}  
         let pixels 
@@ -327,49 +327,53 @@ class Panorama extends THREE.EventDispatcher{
             this[type+'Tex'] = texture 
             if(getRangeFun){ 
                 if(type == 'ir'){ 
-                    /* let p = [range.minPixel_, range.maxPixel_].map(index=>{
+                    let p = [range.minPixel_, range.maxPixel_].map(index=>{
                         let row = Math.floor(index / texture.image.width)
                         let col = index % texture.image.width
                         return {x:col,y:row}
                     })
                     range.minPixel = p[0]
-                    range.maxPixel = p[1]  */
+                    range.maxPixel = p[1] 
+                    
+                    
                     let pixelCount = texture.image.width * texture.image.height
                     const stopMemberCount = 50;
                     
                     
-                    (['min','max']).forEach(name =>{
+                   (['min','max']).forEach(name =>{
                         let value = range[name]
                         let groups = []
                         let isNeigh = (A,B)=>{
                             return (Math.abs(A.x - B.x)<=1 || Math.abs(A.x - B.x) == texture.image.width-1) && Math.abs(A.y - B.y)<=1
                         }
                         for(let i=0;i<pixelCount;i++){
-                            if(Math.abs(value - pixels[i]) < 2 ){
+                            if(Math.abs(value - pixels[i]) == 0 ){
                                 let row = Math.floor(i / texture.image.width)
                                 let col = i % texture.image.width
                                 let data = {x:col, y:row, value: pixels[i]}
-                                Potree.Common.pushToGroupAuto([data], groups, isNeigh/* , recognizeGroup */)
+                                Potree.Common.pushToGroupAuto([data], groups, isNeigh )
                                 if(groups.some(e=>e.length > stopMemberCount && e.some(e=>e==range[name]))){
                                     break
                                 }
                             }
                         } 
                         let groups2 = groups.filter(e=>e.length>1)
-                        if(groups2.length == 0) groups2 = groups
+                        if(groups2.length < 3) groups2 = groups
                         groups2.forEach(group=>{//x的因边界不好写,就只判断y尽量接近中间且范围不大不小即可
                             group.sort((a,b)=>{return a.y-b.y})
                             let minY = group[0].y
                             let maxY = group[group.length-1].y
                             let centerY = (minY + maxY) / 2
                             let rectRatio = (maxY - minY) * 1//除非竖的一列,否则一般y范围越大越好  Math.abs(2 - Potree.math.getBaseLog(maxY - minY, group.length)) //范围圆润度, 最好个数是y范围的平方
-                            group.score = group.length * 0.4 + rectRatio - Math.abs(texture.image.height/2 - centerY) * 0.02 //y尽量接近中间
+                            group.score = group.length * 0.2 + rectRatio - Math.abs(texture.image.height/2 - centerY) * 0.5 //y尽量接近中间
+                             
                             group.center = group[Math.floor(group.length/2)] //忽略是否横向的中间
                         })
                         groups2.sort((b,a)=>{return a.score - b.score})
                         range[name+'Pixel'] = groups2[0]?.center  
-                        //console.log('groups2', this.id, name,groups2)
-                    })
+                        //range[name+'PixelGroup'] = groups2
+                        console.log('groups2', this.id, name,groups2)
+                    })  
                     
                 }
                 range.min /= 10, range.max /= 10

+ 4 - 5
src/custom/objects/Magnifier.js

@@ -38,7 +38,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
         { 
             let density
             let sizeType
-            let colorType
+            let colorType = new Map()
             let opacityBefore = new Map()
             let sizeBefore = new Map()
             let visiMap = new Map()
@@ -50,7 +50,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
                 viewer.scene.pointclouds.forEach(e=>{//因为更改pointDensity时会自动变opacity,所以这项最先获取
                     visiMap.set(e,e.visible)
                     e.visible = Potree.Utils.getObjVisiByReason(e, 'datasetSelection'); //先将隐藏的点云显示
-                
+                    colorType.set(e, e.material.activeAttributeName)  
                     opacityBefore.set(e,e.temp.pointOpacity)  
                     sizeBefore.set(e,e.temp.pointSize)  
                 }) 
@@ -64,8 +64,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
                     sizeType = e.material.pointSizeType  
                     e.material.pointSizeType = Potree.config.material.pointSizeType  
                      
-                    //材质
-                    colorType = e.material.activeAttributeName
+                    //材质 
                     e.material.activeAttributeName = 'rgba'
                     e.changePointOpacity(1) 
                     //e.changePointSize(Potree.config.material.realPointSize, true)
@@ -81,7 +80,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
                     
                     e.visible = visiMap.get(e)                      
                     e.material.pointSizeType = sizeType
-                    e.material.activeAttributeName = colorType  
+                    e.material.activeAttributeName = colorType.get(e)  
                     e.changePointOpacity(opacityBefore.get(e))  
                     //e.changePointSize(sizeBefore.get(e)) 
                 })  

+ 109 - 67
src/custom/objects/Monitor.js

@@ -4,7 +4,7 @@ import * as THREE from "../../../libs/three.js/build/three.module.js";
 import BasicMaterial from '../materials/BasicMaterial.js'  
 
 import {TextSprite} from "./TextSprite.js"; 
-
+//import DepthBasicMaterial from "../materials/DepthBasicMaterial.js";
 import math from '@sdk/utils/math'  
 /* import SecurityCamera from '../core/cameras/SecurityCamera'
 import SecurityControls from '../core/controls/SecurityControls' */
@@ -27,15 +27,17 @@ const vec1 = new THREE.Vector3(),
     vec3 = new THREE.Vector3(),
     quat1 = new THREE.Quaternion(),
     quat2 = new THREE.Quaternion()
-let cameraModel
+let cameraModel, loadingCamModel
+
 
+//测试场景:  http://192.168.0.25/mix3d/#/home/671  潘少  Aa123456  http://192.168.0.25/epg.html?m=YZL-jm-lrZcWxzPaPJ#/tag
 
 
 //接收4dkk的监控 暂不支持修改   可以直接加到模型上,注意所附模型旋转90度后角度才对。
 export default class Monitor extends THREE.Object3D{
     constructor(data, model){
         super()
-         
+        this.isMonitor = true 
         warnHls()
         
         data.video = testUrl
@@ -52,7 +54,8 @@ export default class Monitor extends THREE.Object3D{
         model.add(this)
         
         
-        this.video = videoPlayer.getVideo(data.video,this)
+        let videoUrl = this.getVideoSrc()
+        this.video = videoPlayer.getVideo(videoUrl ,this)
         if (data.video) {
             //console.error('createVideo', this.videoSrc,   this.sid)
             /* this.video.onloadedmetadata = () => {
@@ -74,12 +77,12 @@ export default class Monitor extends THREE.Object3D{
                 this.addEventListener('loadedmetadata', canPlayed)
             }
 
-            if (Hls.isSupported() && data.videoType !== 2) {
+            if (Hls.isSupported() && data.urlType == 1) {
                 //似乎Hls不支持就无法播放
                 let hls = new Hls()
-                hls.loadSource(data.video)
+                hls.loadSource(videoUrl)
                 hls.attachMedia(this.video)
-                hls.on(Hls.Events.ERROR, (event, data) => console.log('HLS加载失败', event, data))
+                hls.on(Hls.Events.ERROR, (event, data) =>{ console.log('HLS加载失败', data.name, event, data)})
                 this.hlsVideoPlayer = hls
             }   
             this.play() // ios需要
@@ -98,7 +101,9 @@ export default class Monitor extends THREE.Object3D{
             opacity: 0.1,
             side: THREE.DoubleSide,
             depthTest: false,
-        })
+        })  
+         
+        
         // 监控视频材质
         this.videoMat = new BasicMaterial({
             map: new THREE.VideoTexture(this.video),
@@ -109,29 +114,32 @@ export default class Monitor extends THREE.Object3D{
         })
         // 摄像头
         if (!cameraModel) {
-            viewer.loadModel({fileType:'glb', url:`${Potree.resourcePath}/models/glb/monitor.glb`},(model)=>{
-                console.log('load monitor glb')
-                this.cameraModel = model.children[0].children[0]
-                this.cameraModel.geometry.translate(30, 50, -10)
-                this.cameraModel.quaternion.setFromEuler(new THREE.Euler(Math.PI / 2, Math.PI, 0))
-                this.obj3d.add(this.cameraModel)
-                model.parent.remove(model)
-                cameraModel = this.cameraModel.clone()
-                this.modelLoaded()
-            })
-        }else{
-            this.cameraModel = cameraModel.clone()
-            this.obj3d.add(this.cameraModel)
+            if(!loadingCamModel){
+                loadingCamModel = true
+                viewer.loadModel({fileType:'glb', url:`${Potree.resourcePath}/models/glb/monitor.glb`},(model)=>{
+                    cameraModel = model.children[0].children[0] 
+                    cameraModel.geometry.translate(30, 50, -10)
+                    cameraModel.quaternion.setFromEuler(new THREE.Euler(Math.PI / 2+0.24, Math.PI, 0))
+                    cameraModel.name = 'cameraModel' 
+                    console.log('load monitor glb', cameraModel.uuid)
+                    model.parent.remove(model) 
+                    viewer.scene.monitors.forEach(e=>e.modelLoaded()) 
+                    loadingCamModel = false
+                })
+            }
+        }else{ 
             this.modelLoaded()
         }
         this.updateAspect()
         
-        {
+        if(data.showTitle){ 
+            let group = new THREE.Shim.FollowRootObject(this) //透明有问题,只有放到overlayScene里渲染了
+            
             this.titleLabel = new TextSprite({
                 text: data.name,
                 backgroundColor: { r: 255, g: 255, b: 255, a: 0 },
                 textColor: { r: 255, g: 255, b: 255, a: 1 },
-                textshadowColor: '#888',
+                textshadowColor: '#666',  
                 borderRadius: 2,
                 fontsize: 34,
                 renderOrder: 5,
@@ -140,7 +148,9 @@ export default class Monitor extends THREE.Object3D{
             })
             this.titleLabel.sprite.material.depthTest = this.titleLabel.sprite.material.depthWrite = true
             this.titleLabel.position.set(0, -0.2, 0.1)
-            this.add(this.titleLabel)
+            group.add(this.titleLabel)
+            viewer.scene.overlayScene.add(group)
+            group.name = 'monitorLabel'
         }
         
         
@@ -153,9 +163,9 @@ export default class Monitor extends THREE.Object3D{
             this.position.copy(Potree.Utils.tran4dkkVecInModel(this.position, model))
  
             // target的优先级大于rotation
-            if (data.target) {
+            if (data.data.target) {
                 this.target = Potree.Utils.tran4dkkVecInModel(data.data.target, model) 
-                this.lookAt(data.target)
+                this.lookAt(data.data.target)
             } else {
                 data.data.rotation && this.quaternion.setFromEuler(data.data.rotation)
                 this.target = new THREE.Vector3(0, 0, -1).applyQuaternion(this.quaternion).add(this.position)
@@ -164,12 +174,17 @@ export default class Monitor extends THREE.Object3D{
             
             
             this.roll = 0
+           
+            
             data.data.pitch && (this.pitch = data.data.pitch)
             data.data.yaw && (this.yaw = data.data.yaw)
             data.data.roll && this.setRoll(this.data.data.roll)
+            
+            if(model.props.baseRotation?.x == 0){ //该模型已经矫正,无需旋转90度,但是场景的数据需要,导致monitor和模型不匹配,需要再旋转
+                this.quaternion.copy(Potree.math.convertQuaternion.YupToZup(this.quaternion))
+            }
+            
         }
-        
-        
 
         
         //this.updateInfo(true)
@@ -193,11 +208,28 @@ export default class Monitor extends THREE.Object3D{
         viewer.addEventListener('update', this.events.update   )
         
         window.monitor = this
-        Potree.Utils.setObjectLayers(this,'monitor')
-        
+        Potree.Utils.setObjectLayers(this,'dontIntersect')
+        Potree.Utils.setObjectLayers(this.cylinder.bottom,'monitor')
+        this.cameraModel && Potree.Utils.setObjectLayers(this.cameraModel,'sceneObjects')
     }
     
-    modelLoaded(){
+    getVideoSrc(){ 
+        if(this.data.urlType === 2){
+            let a = this.parent.props.raw.surveillancePath.split('/');      //用户上传的文件
+            a.pop()
+            return a.join('/') + '/' + this.data.fileName
+        }else{
+            return this.data.playUrl
+        } 
+    }
+    
+    modelLoaded(){ 
+        this.cameraModel = cameraModel.clone()
+        this.cameraModel.material = cameraModel.material.clone()
+        this.obj3d.add(this.cameraModel)
+        
+        
+        
         this.cameraModel.addEventListener('mouseover',()=>{
             CursorDeal.add('hoverMonitor')
             this.highlight(true)
@@ -215,6 +247,14 @@ export default class Monitor extends THREE.Object3D{
     
     
     watch(){ 
+    
+        if (!this.videoActive){
+            console.log('monitorError src:', this.video.src)
+            return  viewer.dispatchEvent('monitorError'  )
+        }  
+
+    
+    
         let camera = viewer.mainViewport.camera
         this.updateAspect()
         this.isWatching = true
@@ -228,8 +268,9 @@ export default class Monitor extends THREE.Object3D{
         this.showVideo(true)
         this.video.pause()//先显示出画面
         setTimeout(()=>{
-            viewer.mainViewport.cameraLayers = ['monitor'] //hide others
-        },1000)
+            viewer.mainViewport.cameraLayers = ['monitor'] //hide others 
+            viewer.scene.monitors.forEach(e=>Potree.Utils.updateVisible(e,'watch', e == this  ))
+        },800)
         viewer.mainViewport.view.setRotMode('free')
         viewer.mainViewport.view.setView({
             position: this.getWorldPosition(new THREE.Vector3),
@@ -256,12 +297,13 @@ export default class Monitor extends THREE.Object3D{
         this.cameraModel.material.color.copy(normalColor)
         viewer.mainViewport.view.cancelFlying()
         viewer.mainViewport.cameraLayers = null
+        viewer.scene.monitors.forEach(e=>Potree.Utils.updateVisible(e,'watch', true  ))
         this.video.pause()
         viewer.mainViewport.view.setView({
             position: this.oldState.position,
             quaternion: this.oldState.quaternion,
             
-            onUpdate:(percent)=>{
+            onUpdate:(percent)=>{ 
                 camera.fov = this.fov * (1-percent) + this.oldState.fov * percent
                 camera.updateProjectionMatrix()
             },
@@ -281,7 +323,7 @@ export default class Monitor extends THREE.Object3D{
     showVideo(isShow) {
         //console.warn('showVideo', this.info.sid, isShow )
          
-        if (!this.videoActive) return
+        if (!this.videoActive) return  
 
         if (isShow) {
             /* if (browser.detectIOS()) {
@@ -364,7 +406,7 @@ export default class Monitor extends THREE.Object3D{
         this.videoMat.dispose()
 
         
-        this.titleLabel.dispose()
+        this.titleLabel?.dispose()
         
         this.hlsVideoPlayer && this.hlsVideoPlayer.destroy()
         
@@ -466,24 +508,20 @@ export default class Monitor extends THREE.Object3D{
         }
     }
 
-    // 横滚角
-    setRoll(angle) {
-        this.roll = angle % 360
-        this.obj3d.quaternion.setFromAxisAngle(vec1.set(0, 0, -1), THREE.MathUtils.degToRad(angle))
-    }
- 
- 
-    get yaw() {
-        // 左右转角
-        let lookAt = vec1.copy(this.cylinder.bottom.position).applyQuaternion(this.quaternion)
-        let lookAtXZ = lookAt.setY(0)
-        let frontDir = vec2.set(0, 0, 1)
-        let frontCross = vec3.set(1, 0, 0)
-        let angle = (THREE.MathUtils.radToDeg(lookAtXZ.angleTo(frontDir) * Math.sign(lookAtXZ.dot(frontCross))) + 180) % 360
-        if (angle > 180) angle = angle - 360
+    
+    set pitch(pitch) {
+        pitch = Math.min(Math.max(pitch, -89.9), 89.9) // 防止万向锁
 
-        return angle
+        let yaw =  this.yaw < 0 ? this.yaw + 360 : this.yaw  
+        let upDir = vec1.set(0, 1, 0)
+        let rightDir = vec2.set(1, 0, 0) //.applyQuaternion(this.quaternion)
+        let yawQuat = quat1.setFromAxisAngle(upDir, THREE.MathUtils.degToRad(yaw))
+        let pitchQuat = quat2.setFromAxisAngle(rightDir, THREE.MathUtils.degToRad(pitch))
+        this.quaternion.multiplyQuaternions(yawQuat, pitchQuat)
+
+        //this.updateTarget()
     }
+    
 
     set yaw(yaw) {
         let pitch = this.pitch // 要先计算pitch,防止窜数据
@@ -495,29 +533,33 @@ export default class Monitor extends THREE.Object3D{
 
         //this.updateTarget()
     }
-
-    get pitch() {
-        // 上下转角
+    
+    // 横滚角
+    setRoll(angle) {//因加在子物体上,非0时播放视频是歪的(4dkk也这样)
+        this.roll = angle % 360
+        this.obj3d.quaternion.setFromAxisAngle(vec1.set(0, 0, -1) , THREE.MathUtils.degToRad(angle))
+    }
+    get pitch() {// 上下转角
+        return this.data.data.pitch //xzw改
         let lookAt = vec1.copy(this.cylinder.bottom.position).applyQuaternion(this.quaternion)
         let projectVec = vec2.copy(lookAt).projectOnPlane(vec3.set(0, 1, 0))
         let pitch = THREE.MathUtils.radToDeg(lookAt.angleTo(projectVec) * Math.sign(lookAt.y)) % 180
         if (pitch > 90) pitch = 90 - pitch
 
         return pitch
-    }
-
-    set pitch(pitch) {
-        pitch = Math.min(Math.max(pitch, -89.9), 89.9) // 防止万向锁
+    } 
 
-        let yaw = this.yaw < 0 ? this.yaw + 360 : this.yaw
-        let upDir = vec1.set(0, 1, 0)
-        let rightDir = vec2.set(1, 0, 0) //.applyQuaternion(this.quaternion)
-        let yawQuat = quat1.setFromAxisAngle(upDir, THREE.MathUtils.degToRad(yaw))
-        let pitchQuat = quat2.setFromAxisAngle(rightDir, THREE.MathUtils.degToRad(pitch))
-        this.quaternion.multiplyQuaternions(yawQuat, pitchQuat)
+    get yaw() {// 左右转角  
+        return this.data.data.yaw //xzw改  原先的计算不对,0变180
+        let lookAt = vec1.copy(this.cylinder.bottom.position).applyQuaternion(this.quaternion)
+        let lookAtXZ = lookAt.setY(0)
+        let frontDir = vec2.set(0, 0, 1)
+        let frontCross = vec3.set(1, 0, 0)
+        let angle = (THREE.MathUtils.radToDeg(lookAtXZ.angleTo(frontDir) * Math.sign(lookAtXZ.dot(frontCross))) + 180) % 360
+        if (angle > 180) angle = angle - 360
 
-        //this.updateTarget()
-    }
+        return angle
+    } 
     
 }
 

+ 6 - 3
src/custom/objects/Overlay.js

@@ -49,10 +49,13 @@ export default class Overlay extends THREE.Object3D {
         this.addEventListener('isVisible',updatePlayInSight)
         this.addEventListener('transformChanged',updatePlayInSight) 
         
+        Potree.Utils.setObjectLayers(this,'dontIntersect')
+      
     } 
     
     
     setContent(type, src, autoSize){
+        
         this.mediaType = type
         let loadDone = ()=>{
             autoSize && this.autoSize()
@@ -135,11 +138,11 @@ export default class Overlay extends THREE.Object3D {
         if (!state || state == 'stop') {
             if (!video.paused){
                 video.pause()
-                console.log('videoControl paused ')
+                //console.log('videoControl paused ')
             } 
         }else if(state) {
             if (video.paused){
-                 console.log('videoControl play ')
+                //console.log('videoControl play ')
                 //video = this.loadVideo()
                 video.play()
             }
@@ -164,7 +167,7 @@ export default class Overlay extends THREE.Object3D {
             if(overlay.plane.material.side!=2){ //side为0
                 let dir = overlay.plane.getWorldDirection(new THREE.Vector3) 
                 if(dir.dot(camDir)>0 ){
-                    console.log('dir.dot(camDir)',dir.dot(camDir))
+                    //console.log('dir.dot(camDir)',dir.dot(camDir))
                     return false
                 }
                 //可能看到背面。若能看到正面,视线方向和plane朝向必定为钝角

+ 4 - 2
src/custom/objects/Tag.js

@@ -229,7 +229,7 @@ class Tag extends THREE.Shim.FollowRootObject{
         
         // CursorDeal
         this.lineDragPoint.addEventListener('mouseover',(e)=>{
-            setDragPointState(true)
+            grabbingObject || setDragPointState(true)
         })
         this.lineDragPoint.addEventListener('mouseleave',(e)=>{
             grabbingObject != 'lineDragPoint' && setDragPointState(false)
@@ -304,8 +304,10 @@ class Tag extends THREE.Shim.FollowRootObject{
     
     changePos(info){//注:onMesh时在非平地上拖拽,热点旋转会一直变 
         this.position.copy(info.position)
-        this.normal.copy(info.normal)
+        this.normal.copy(info.normal) 
+        let root = this.root
         this.root = info.root
+        root != this.root && this.updateMatrixWorld() //防止拖动到另一个scale不同的模型上时sprite会缩放闪烁
         this.setNorQua()
         this.updatePose() 
         this.dispatchEvent('posChanged')

+ 14 - 10
src/custom/objects/TextSprite.js

@@ -15,8 +15,12 @@ export class TextSprite extends THREE.Object3D{
 	constructor( options={}){ 
         super()
 		let map = new THREE.Texture();
-		map.minFilter = THREE.LinearFilter;//清晰一些?
-		map.magFilter = THREE.LinearFilter;
+        /* map.generateMipmaps = true
+		map.minFilter = THREE.LinearMipmapLinearFilter  */ //这个比LinearFilter平滑所以模糊点
+        map.minFilter = THREE.LinearFilter;//缩小效果都不好,sizeInfo尽量放大些(但要跟看到的差不多宽),用框选工具测出像素宽度大于map.image.width即可
+		map.magFilter = THREE.NearestFilter ; //试过 当可见宽度稍大于和贴图宽度时,放大后可以很清晰。可见宽度太大有锯齿。
+        //width2d一般设置为200
+        
         
         this.sprite = new Sprite( Object.assign({
                 root:this
@@ -37,6 +41,7 @@ export class TextSprite extends THREE.Object3D{
         this.textBorderColor = options.textBorderColor ? Common.CloneObject(options.textBorderColor):{ r: 0, g: 0, b: 0, a: 1.0 };
 		this.backgroundColor = options.backgroundColor ? Common.CloneObject(options.backgroundColor):{ r: 255, g: 255, b: 255, a: 0.7 };
 		this.textColor = options.textColor ? Common.CloneObject(options.textColor):{r: 0, g: 0, b: 0, a: 1.0};
+        this.textshadowColor = options.textshadowColor  
         this.borderColor = options.borderColor  ? Common.CloneObject(options.borderColor):{ r: 0, g: 0, b: 0, a: 0.0 };
 		this.borderRadius = options.borderRadius || 6;
         this.margin = options.margin
@@ -198,7 +203,7 @@ export class TextSprite extends THREE.Object3D{
                 context.shadowOffsetX = 0
                 context.shadowOffsetY = 0
                 context.shadowColor = this.textshadowColor //'red'
-                context.shadowBlur = (this.textShadowBlur || this.fontSize/3) * r
+                context.shadowBlur = (this.textShadowBlur || this.fontsize/6) * r
             }
             context.fillText(texts[i], x, y)
             
@@ -207,16 +212,15 @@ export class TextSprite extends THREE.Object3D{
             y += actualBoundingBoxDescent + textBorderThick + lineSpace
         } 
         
-		let texture = new THREE.Texture(canvas);
-		texture.minFilter = THREE.LinearFilter;
-		texture.magFilter = THREE.LinearFilter;
-		texture.needsUpdate = true;
-		//this.material.needsUpdate = true; 
+		/* let texture = new THREE.Texture(canvas); 
+		texture.needsUpdate = true; */
+		this.sprite.material.map.image =  canvas
+        this.sprite.material.map.needsUpdate = true; 
         
-        if(this.sprite.material.map){
+        /* if(this.sprite.material.map){
             this.sprite.material.map.dispose()
         }
-		this.sprite.material.map = texture;
+		this.sprite.material.map = texture; */
 		 
 
         let oldScale = this.sprite.scale.clone()  

+ 29 - 12
src/custom/objects/tool/Path.js

@@ -27,11 +27,11 @@ const arrowCountMax = 1000; //箭头总数不能超过这个值。 The count val
 let lastArrowCamPos,  lastArrowCount = 0
  
 const depthProps = {
-    useDepth : true , 
+    useDepth : true ,  
     //startClipDis  : 0.5,
-    clipDistance : 2,//消失距离      
+    clipDistance : 0.5,//消失距离      
     //startOcclusDis: 0.5,
-    occlusionDistance: 0.7,//变为backColor距离 
+    occlusionDistance: 0.3,//变为backColor距离 
     maxOcclusionFactor:0.9,
     maxClipFactor:1
 }
@@ -502,7 +502,12 @@ export class Path extends ctrlPolygon{
         if(this.color == color)return
         this.color = color  
         let c = new THREE.Color().set(this.color) 
-        this.titleLabel.setTextColor({r: c.r*255, g:c.g*255, b:c.b*255, a:0.5})
+        
+        
+        let hsb = new THREE.Color().set(this.color).getHSV() 
+        let textColor = new THREE.Color().setHSV(hsb.h, hsb.s, 100) //make bright full
+                
+        this.titleLabel.setTextColor({r: textColor.r*255, g:textColor.g*255, b:textColor.b*255, a:0.95})
         this.updateSelectStyle()  //apply color
         
         viewer.dispatchEvent('content_changed')
@@ -557,18 +562,23 @@ export class Path extends ctrlPolygon{
                 let curve = new THREE.CatmullRomCurve3(points, false    )  
                 curve.UtoTMapArr = [] //用于存储 getSpacedPoints得到的点对应points的百分比对应
                 //window.arcLengthDivisions  && (curve.arcLengthDivisions = arcLengthDivisions) //默认200,但改为1也没变化呀
+                let oldCount = count
                 count = Math.max(2, Math.round(this.getTotalDistance() * 400)),  points = curve.getSpacedPoints(count-1) //拆分为更密集的点
                 this.curve = curve
                 //减少点数(拐弯的部分紧凑些,直线部分宽松些):
                 let lastVec  
                 let newPoints = []
                 this.UtoTMapArr = []
+                let pointIndexs = []//找出新点中对应原先控制点的index,这些点必须加入拐点,否则会出现控制点偏移path(当它所在部分接近直线时) 
+                for(let n=1;n<oldCount-1;n++){
+                    pointIndexs.push( curve.UtoTMapArr.findIndex(e=>e>= n / (oldCount-1) ) )
+                }                
                 for(let i=0;i<count;i++){
                     let point = points[i];
                     let last = points[i-1]
                     let next = points[i+1]
                     
-                    if(i == 0 || i == count-1) {
+                    if(i == 0 || i == count-1 ) {
                         newPoints.push(point) //直接加入
                         this.UtoTMapArr.push(i == 0 ? 0 : 1)
                     }
@@ -576,7 +586,7 @@ export class Path extends ctrlPolygon{
                         let curVec = new THREE.Vector3().subVectors(next,point)
                         if(!lastVec) lastVec = curVec
                         if(i>1){// 和上一个加入点的vec之间的夹角如果过大就加入 
-                            if(curVec.angleTo(lastVec) > 0.05){//最小角度
+                            if(pointIndexs.includes(i) || curVec.angleTo(lastVec) > 0.05){//最小角度
                                 newPoints.push(point)
                                 this.UtoTMapArr.push(curve.UtoTMapArr[i])
                                 lastVec = curVec
@@ -920,19 +930,24 @@ export class Path extends ctrlPolygon{
     updateSelectStyle(){
         
         
-        let c = new THREE.Color().set(this.color).getHSL({ h: 0, s: 0, l: 0 })
-        
+        //let c = new THREE.Color().set(this.color).getHSL({ h: 0, s: 0, l: 0 })
+        let hsv = new THREE.Color().set(this.color).getHSV()
         let color, arrowColor  
         if(this.selectStates.click){
             color = '#00C8AF'
             arrowColor = '#ffffff'
+             
         }else if(this.selectStates.hover){  
-            color = new THREE.Color().setHSL(c.h, c.s, c.l - 0.1 )   
-            arrowColor = new THREE.Color().setHSL(c.h, c.s, c.l >= 0.4 ? c.l - 0.3 : c.l + 0.3 )  
-        }else{
-            arrowColor = new THREE.Color().setHSL(c.h, c.s, c.l >= 0.4 ? c.l - 0.3 : c.l + 0.3 )  
+            /* color = new THREE.Color().setHSL(c.h, c.s, c.l - 0.1 )   
+            arrowColor = new THREE.Color().setHSL(c.h, c.s, c.l >= 0.4 ? c.l - 0.3 : c.l + 0.3 )  */ 
+            color = new THREE.Color().setHSV(hsv.h, hsv.s, hsv.v - 10 )   
+            arrowColor = new THREE.Color().setHSV(hsv.h, hsv.s, hsv.v >= 40 ? hsv.v - 30 : hsv.v + 30 )
             
+        }else{
+            //arrowColor = new THREE.Color().setHSL(c.h, c.s, c.l >= 0.4 ? c.l - 0.3 : c.l + 0.3 )  
+            arrowColor = new THREE.Color().setHSV(hsv.h, hsv.s, hsv.v >= 40 ? hsv.v - 30 : hsv.v + 30 )  
             color = this.color
+            
         }
         
         if(this.arrows){
@@ -942,6 +957,8 @@ export class Path extends ctrlPolygon{
         }
         ([this.edge, this.endCaps[0].children[0]].forEach(e=>{ 
             e.material.color.set(color)
+            e.material.uniforms.maxClipFactor.value = this.selectStates.click ? 0.4 : this.selectStates.hover ? 0.6 : depthProps.maxClipFactor
+            e.material.uniforms.occlusionDistance.value = this.selectStates.click ? 0.6 : this.selectStates.hover ? 0.7 : depthProps.occlusionDistance
         }))
     }
     

+ 8 - 10
src/custom/objects/tool/TransformControls.js

@@ -184,7 +184,7 @@ var TransformControls = function ( camera, domElement, options ) {
 
 	// Detatch from object
 	this.detach = function () {
-
+        console.warn('detach')
 		this.object = undefined;
 		this.axis = null;
 		//Config.keyCon = true;//add
@@ -474,19 +474,16 @@ var TransformControls = function ( camera, domElement, options ) {
 			if ( axis.indexOf( 'Z' ) === - 1 ) offset.z = 0;
 
 			if ( space === 'local' && axis !== 'XYZ' ) {
-                //xzw 加,否则会反向---------------
-                object.scale.x < 0 && (offset.x *= -1)
-                object.scale.y < 0 && (offset.y *= -1)
-                object.scale.z < 0 && (offset.z *= -1)
-                //---------------------------------
+                //xzw 加,否则会反向-----three官网也有问题----2025.4又改了一下(之前改完没测试吗=,=),经测试没问题---
+                //object.scale.x < 0 && (offset.x *= -1) 
+                object.scale.y < 0 && (offset.x *= -1, offset.y *= -1)
+                object.scale.z < 0 && (offset.x *= -1, offset.z *= -1)   
 				offset.applyQuaternion( quaternionStart ).divide( parentScale );
-
 			} else {
-
 				offset.applyQuaternion( parentQuaternionInv ).divide( parentScale );
 
 			}
-
+            
 			object.position.copy( offset ).add( positionStart );
 
 			// Apply translation snap
@@ -640,7 +637,7 @@ var TransformControls = function ( camera, domElement, options ) {
 			}
 			//add:
             
-            
+            this.options.minScale && object.scale.max(this.options.minScale)
            
             object.dispatchEvent({
                 type: "scale_changed" , byControl:true
@@ -1205,6 +1202,7 @@ var TransformControlsGizmo = function (options) {
 	};
 
 	var pickerRotate = {
+
 		X: [    //xzw 由原先全弧度改为一半弧度(Math.PI),否则在背面也会hover到
 			[ new THREE.Mesh( new THREE.TorusBufferGeometry( 1, 0.06, 4, 24, options.rotFullCircle ? Math.PI*2 : Math.PI ), matInvisible ), [ 0, 0, 0 ], [ 0, - Math.PI / 2, - Math.PI / 2 ]],
 		],

+ 26 - 33
src/custom/potree.shim.js

@@ -274,11 +274,8 @@ Utils.loadSkybox = function(path, oldSky, callback ) {
   
 
 Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera, viewer, pointclouds, pickParams = {} ) {
-    //getIntersectByDepthTex
-    /* let result = viewer.edlRenderer.depthTexSampler.sample(viewport, mouse)//add
-    if(result != 'unsupport')return result
-      */
-    
+  
+    //let startTime = performance.now() 
      
     
     if(!pointclouds || pointclouds.filter(e=>Potree.Utils.getObjVisiByReason(e, 'datasetSelection')).length == 0)return
@@ -290,28 +287,11 @@ Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera
     if(pickParams.ifCenter){
         pickParams.x = Math.round(resolution.x / 2)
         pickParams.y = Math.round(resolution.y / 2)
-    }else{
-        /* if(viewport){ //转换到类似整个画面时 
-            pickParams.x = mouse.x;
-            pickParams.y = viewport.resolution.y - mouse.y;
-        }else{ 
-            pickParams.x = mouse.x;
-            pickParams.y = renderer.domElement.clientHeight - mouse.y; 
-        }  */
-        
+    }else{ 
         pickParams.x = mouse.x; 
         pickParams.y = resolution.y - mouse.y; 
     }
-    
-    
-    
      
-    //console.log('getMousePointCloudIntersection')
-      
-    /* if(!raycaster){
-        raycaster = new THREE.Raycaster();
-        raycaster.setFromCamera(pointer, camera); 
-    }  */
     
     let raycaster = new THREE.Raycaster();
     raycaster.setFromCamera(pointer, camera); 
@@ -443,7 +423,7 @@ Utils.getMousePointCloudIntersection = function(viewport, mouse, pointer, camera
         }  
     }
     
-    
+    //console.log('pick',   performance.now() - startTime )
     
     
     
@@ -493,7 +473,7 @@ Utils.pixelsArrayToDataUrl = function(pixels, width, height, compressRatio = 0.7
     imageData.data.set(pixels);
     context.putImageData(imageData, 0, 0);
 
-    let dataURL = canvas.toDataURL(compressRatio);
+    let dataURL = canvas.toDataURL(compressRatio < 1 ? 'image/jpeg' : 'image/png', compressRatio);
 
     return dataURL;
 }
@@ -1025,9 +1005,19 @@ Utils.combineImgs = async (imgs, compressRatio, width, height)=>{//拼合图片
                 img.index = {i,j}
                 img.onload = ()=>{ 
                     loadCount++
-                    context.drawImage(img, img.index.i * img.width,  img.index.j * img.height, img.width, img.height)
-                    if(loadCount == amount){ 
-                        var dataUrl = canvas.toDataURL('image/png',compressRatio)
+                    let startX = img.index.i * img.width,  startY = img.index.j * img.height
+                    if(imgs[i][j].rot180){ //旋转180度 
+                        context.save();// 保存当前画布状态
+                        context.translate(startX + img.width/2, startY + img.height/2),  // 移动到旋转中心点(图像中心)旋转
+                        context.rotate(Math.PI);
+                        startX = -img.width/2, startY = -img.height/2
+                    }
+                    context.drawImage(img, startX,  startY, img.width, img.height ) 
+                    imgs[i][j].rot180 && context.restore();// 恢复画布状态
+                    
+                    if(loadCount == amount){
+                        
+                        var dataUrl = canvas.toDataURL(compressRatio < 1 ? 'image/jpeg' : 'image/png', compressRatio)
                         context.clearRect(0,0,width,height)
                         resolve(dataUrl)
                     }
@@ -1039,8 +1029,9 @@ Utils.combineImgs = async (imgs, compressRatio, width, height)=>{//拼合图片
 }
 
 Utils.tran4dkkVecInModel = (vec, model)=>{//将四维看看里的坐标转换成在此平台模型上的坐标(主要是3dtiles需要平移) 见load4dkkpanos
+    //if(model.fileType != '3dTiles') return Potree.math.convertVector.YupToZup(vec)
     return Potree.math.convertVector.YupToZup(vec).applyMatrix4(model.posRot1MatrixInvert)  //若要全局坐标,可以直接像pano那样转换,多乘个matrix
-}
+} 
 
 
 BinaryLoader.prototype.load = function(node, callback){//解析点云
@@ -1369,7 +1360,7 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 		let visible = insideFrustum;
 		visible = visible && !(numVisiblePoints + node.getNumPoints() > Potree.pointBudget);
 		visible = visible && !(numVisiblePointsInPointclouds.get(pointcloud) + node.getNumPoints() > pointcloud.pointBudget); // pointcloud.pointBudget一直是Infinity
-		visible = visible && level <= maxLevel /* && level >= minLevel */ ;  //< 改为 <=
+		visible = visible && level <= maxLevel ;  //< 改为 <=
 		//visible = visible || node.getLevel() <= 2;
         let pcWorldInverse = pointcloud.matrixWorld.clone().invert();
         /* let m = pcWorldInverse.elements 
@@ -1487,9 +1478,11 @@ Potree.updateVisibility = function(pointclouds, camera, areaSize){
 			Potree.lru.touch(node.geometryNode);//在缓存中计入点云
 			node.sceneNode.visible = true;
 			node.sceneNode.material = pointcloud.material;
-
-			/* level >= minLevel && */visibleNodes.push(node);
-			/* level >= minLevel && */pointcloud.visibleNodes.push(node);
+             
+ 
+            let show = level >= minLevel && (!Potree.hideParentNode || node.children.some(e=>!e || !e.isTreeNode())) //满子集且都加载好的不显示
+			show && visibleNodes.push(node);
+			show && pointcloud.visibleNodes.push(node);
             
             //if(Potree.settings.sortNodesDis){//add
             if(pointcloud.material.opacity < 1 && Potree.settings.notAdditiveBlending ){ 

+ 6 - 1
src/custom/settings.js

@@ -274,7 +274,9 @@ const config = {//配置参数   不可修改
         magnifierContent:7,
         volume:8,
         transformationTool:9,
-       
+        
+        
+        
         map:10,
         mapObjects:11,//default
         
@@ -284,11 +286,14 @@ const config = {//配置参数   不可修改
         onlyMapVisi:13,//只能mapViewer可见
         mapUnvisi:14,//只有mapViewer不可见
         sideVisi:15,//只有侧面可见
+       
         
         bg: 16, 
         bg2: 17,
         layer1: 18,// 备用1
         layer2: 19,// 备用2
+        
+        dontIntersect:20
     },
     
     renderOrders:{ //会影响到绘制、pick时的顺序。

+ 57 - 6
src/custom/start.js

@@ -362,8 +362,9 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
                             } 
                         }
                         if(dataset.has_ir){//红外热成像漫游点数据
-                            let panoIrUrl = `${Potree.settings.urls.prefix1}/testdata/${Potree.settings.number}/data/${pointcloud.sceneCode}/imagemap/types.json`
-                            Potree.loadFile(panoIrUrl,null,(e)=>{
+                            pointcloud.typesUrl = `${Potree.settings.urls.prefix1}/${Potree.settings.webSite2 || Potree.settings.webSite}/${pointcloud.sceneCode}/data/${pointcloud.sceneCode}/imagemap/`
+                            let typesUrl = pointcloud.typesUrl + 'types.json'
+                            Potree.loadFile(typesUrl,null,(e)=>{
                                 e.imagemap_types.forEach(o=>{
                                     o.uuids.forEach(uuid=>{
                                         //if(o.property == 'temp')return //只要ir
@@ -919,12 +920,15 @@ export function mergeEditStart(dom, mapDom){
                                 model.position.add(location)
                             }
                         }else{
+                             
                             MergeEditor.moveBoundCenterTo(model, location )   
                             if(prop.raw?.orientation){
                                 model.rotation.y = parseFloat(prop.raw.orientation)  
                             }  
                             if(prop.is4dkkModel){
-                                console.warn('遇到is4dkkModel的且有经纬度的mesh,但不是3dtiles! 位置估计不准', model)
+                                console.warn('遇到is4dkkModel的且有经纬度的mesh,但不是3dtiles!看看位置准不准', model)
+                                //4dkk应该是可以对的上的。但如果是3dtiles非4dkk的,目前没办法对准,cesium是可以
+                                
                                 //看见的场景说是市场不会带rtk的。所以我们这边标品也没存rtk的坐标信息。和产品聊了,不处理。意思就是,只有激光场景开启了rtk的rtkLocation才有值
                                 /* if(model.panos?.length){//只能通过漫游点经纬度来校准 
                                     //但这时候panos还没加载。。。。
@@ -1021,7 +1025,7 @@ export function mergeEditStart(dom, mapDom){
                 }  
                 let maintainCenter = (e)=>{ 
                     //MergeEditor.maintainBoundXY(model) 
-                    e.by2d || MergeEditor.maintainBoundCenter(model) 
+                    e.by2d || model.atPath || MergeEditor.maintainBoundCenter(model) 
                     updateBound()
                     model.dispatchEvent({type:'transformChanged',  byControl:e.byControl})  
                 }
@@ -1056,7 +1060,7 @@ export function mergeEditStart(dom, mapDom){
             if(prop.isFirstLoad){  
                 
                 if(model.hasLonLat || !moveModelWhenLoad){
-                    setTimeout(()=>{MergeEditor.focusOn(model)} , 1)
+                    //setTimeout(()=>{MergeEditor.focusOn(model)} , 1) //由2d控制
                 }else{
                     MergeEditor.moveBoundCenterTo(model, new THREE.Vector3(0,0,0)) 
                 }
@@ -1251,8 +1255,55 @@ var changeLog = ()=>{
  
  
  
+//隧道截图  暂时测试时要等当前全景图都加载完。要保持放大才会4k
+window.screenshotTube = (width = 2048, height = 1024, initDir, compress=1)=>{ 
+    
+    let dataUrls = []
+    
  
- 
+    let oldFov = viewer.mainViewport.camera.fov 
+    viewer.setFOV(90);
+    if(initDir){
+        initDir = new THREE.Vector3(initDir.x, initDir.y, 0) //水平、垂直于墙面 
+        viewer.mainViewport.view.direction = initDir  //初始角度 
+    } 
+         
+    let yaw = viewer.mainViewport.view.yaw
+    let camDirs = [{yaw, pitch:0},{yaw:yaw + Math.PI,pitch:Math.PI/2}, {yaw:yaw + Math.PI, pitch:0}]
+    
+    
+     
+    
+    let screenshot = (curIndex)=>{  
+        viewer.mainViewport.view.yaw = camDirs[curIndex].yaw
+        viewer.mainViewport.view.pitch = camDirs[curIndex].pitch
+        var {getImagePromise, finishPromise} = viewer.startScreenshot({ type: 'default',  hideMarkers: true  }, width, height  )
+        finishPromise.done( ({dataUrl}) => {
+            console.log('get', curIndex)
+            dataUrls.push(dataUrl)
+            if(curIndex == 2){//finish
+                dataUrls = [dataUrls.map(e=>{return {dataUrl:e, width, height}})]
+                dataUrls[0][0].rot180 = true 
+                Potree.Utils.combineImgs(dataUrls, compress).then((dataUrlWhole)=>{
+                    Potree.Common.downloadFile(dataUrlWhole, '隧道.png') 
+                    viewer.setFOV(oldFov);
+                })  
+                viewer.mainViewport.view.yaw = yaw
+            }else{
+                screenshot(++curIndex)
+            }  
+        }) 
+    }
+    if(viewer.images360.latestRequestMode == 'showPanos'){
+        screenshot(0)
+    }else{
+        Potree.settings.displayMode = 'showPanos'
+        viewer.images360.addEventListener('endChangeMode',screenshot.bind(this,0),{once:true})
+    }
+    
+                
+               
+}
  
 
    /* 

Diferenças do arquivo suprimidas por serem muito extensas
+ 492 - 395
src/custom/three.shim.js


+ 14 - 4
src/custom/utils/Common.js

@@ -278,10 +278,20 @@ var Common = {
         return get(url)
     },
      
-    
-    
-    
-    
+    getBoundPoints(bound, matrixWorld ){
+        let points = [  
+            new THREE.Vector3(bound.min.x, bound.min.y, bound.min.z ),
+            new THREE.Vector3(bound.min.x, bound.min.y, bound.max.z ), 
+            new THREE.Vector3(bound.min.x, bound.max.y, bound.min.z ),
+            new THREE.Vector3(bound.max.x, bound.min.y, bound.min.z ),
+            new THREE.Vector3(bound.max.x, bound.max.y, bound.min.z ),
+            new THREE.Vector3(bound.max.x, bound.min.y, bound.max.z ),
+            new THREE.Vector3(bound.min.x, bound.max.y, bound.max.z ),
+            new THREE.Vector3(bound.max.x, bound.max.y, bound.max.z ),
+        ];
+        matrixWorld && points.forEach(e=>e.applyMatrix4(matrixWorld))
+        return points
+    },
     
     //---------------------------
     

+ 3 - 3
src/custom/utils/CursorDeal.js

@@ -7,13 +7,13 @@ import Common from './Common.js'
 
 var CursorDeal = {
     priorityEvent : [//在前面的优先级高
-        
+        {'grabbing':'grabbing'},//通用
+        {'hoverGrab':'grab'},//通用
         { pen_delPoint: `url({Potree.resourcePath}/images/polygon_mark/pic_pen_sub.png),auto`},
         { pen_addPoint: `url({Potree.resourcePath}/images/polygon_mark/pic_pen_add.png),auto`},
         { pen: `url({Potree.resourcePath}/images/polygon_mark/pic_pen.png),auto`},
          
-        {'grabbing':'grabbing'},//通用
-        {'hoverGrab':'grab'},//通用
+        
         {'pointer':'pointer'},//通用
         
         {'hoverMonitor':'pointer'}, 

+ 5 - 3
src/custom/utils/History.js

@@ -4,6 +4,8 @@ import * as THREE from "../../../libs/three.js/build/three.module.js";
 
 import Common from './Common.js'
 
+let sid = 0
+
 class History extends THREE.EventDispatcher{
     
     constructor(o){ 
@@ -15,7 +17,7 @@ class History extends THREE.EventDispatcher{
         this.getData = o.getData        //获取数据的方法
         
         this.dataBefore 
-        
+        this.sid = sid++
         
        
         ;(o.viewer || viewer).inputHandler.addEventListener('keydown', (e)=>{
@@ -42,7 +44,7 @@ class History extends THREE.EventDispatcher{
             unExist || this.redoList.push(last); 
             unExist && this.undo()//找不到就回退下一个。
             this.dispatchEvent('undo')
-            //console.log('undo',last)
+             console.log(this.sid, 'undo', this.undoList.length )
         } 
     }
     
@@ -77,7 +79,7 @@ class History extends THREE.EventDispatcher{
     writeIn(data ){ 
         this.redoList.length = 0; //一旦录入新的操作,就不允许undo了
         //console.log('writeIn',  data)    
-        this.undoList.push(data );   
+        this.undoList.push(data );    
     }
     
     

+ 3 - 0
src/custom/utils/math.js

@@ -661,6 +661,9 @@ var math = {
     
     getKelvinFromCelsius(c){ //摄氏度->开尔文
         return c + 273.1 //273.15   算法的值是整数然后除以10所以只保留一位小数
+    },
+    getCelsiusFromKelvin(c){  
+        return c - 273.1  
     }
 };
 

+ 15 - 10
src/custom/viewer/ViewerNew.js

@@ -3650,7 +3650,7 @@ export class Viewer extends ViewerBase{
         else{
             if(params.viewport.name == "mapViewport" )cameraLayers = ['bothMapAndScene', 'light']
             else {
-                cameraLayers = ['sceneObjects', 'light', 'bothMapAndScene', 'monitor' ];
+                cameraLayers = ['sceneObjects', 'light', 'bothMapAndScene', 'monitor', 'dontIntersect' ];
                 if(!params.useModelOnRT){
                      cameraLayers.push('model')
                 } 
@@ -3801,7 +3801,7 @@ export class Viewer extends ViewerBase{
 
     
 
-    startScreenshot(info={},  width=800, height=400, compressRatio ){//add
+    startScreenshot(info={},  width=800, height=400, compressRatio=1 ){//add
         //let deferred = info.deferred || $.Deferred();
         let getImageDeferred = info.getImageDeferred || $.Deferred();
         let finishDeferred = info.finishDeferred || $.Deferred();
@@ -3870,7 +3870,7 @@ export class Viewer extends ViewerBase{
                         viewer.dispatchEvent({type:'resize', viewport:viewer.mapViewer.viewports[0]}) //借用viewer通知lineMaterial resize
                         viewerMaster.renderOverlay()
                     } */
-                    var dataUrl = canvas.toDataURL('image/png',compressRatio) 
+                    var dataUrl = canvas.toDataURL(compressRatio < 1 ? 'image/jpeg' : 'image/png', compressRatio) 
                 }
                 return dataUrl
             }
@@ -5443,6 +5443,7 @@ export class Viewer extends ViewerBase{
                 return console.warn('已设置过pointStatesBefore!')
             }
             this.pointStatesBefore = {
+                colorType: new Map(),
                 opacity : new Map(), 
                 size: new Map(), 
                 density:Potree.settings.pointDensity,
@@ -5452,7 +5453,7 @@ export class Viewer extends ViewerBase{
             
             viewer.scene.pointclouds.forEach(e=>{
                 this.pointStatesBefore.opacity.set(e, e.temp.pointOpacity)  //因为更改pointDensity时会自动变opacity,所以这项最先获取
-                this.pointStatesBefore.colorType = e.material.activeAttributeName; 
+                this.pointStatesBefore.colorType.set(e,e.material.activeAttributeName) 
                 fitPointsize && this.pointStatesBefore.size.set(e,e.temp.pointSize) //这项不一定有用,因为会被后期覆盖
             }) 
             
@@ -5460,7 +5461,7 @@ export class Viewer extends ViewerBase{
             if(fitPointsize)Potree.settings.sizeFitToLevel = true 
             
             viewer.scene.pointclouds.forEach(e=>{   
-                e.material.activeAttributeName = 'rgba'; 
+                e.material.activeAttributeName = this.pointStatesBefore.colorType.get(e) == 'ir'?'ir':'rgba'; 
                 e.material.shape = Potree.PointShape['SQUARE']
                 fitPointsize && e.changePointSize(Potree.config.material.realPointSize, true) 
                 e.changePointOpacity(1)      
@@ -5477,7 +5478,7 @@ export class Viewer extends ViewerBase{
             
             
             viewer.scene.pointclouds.forEach(e=>{   
-                e.material.activeAttributeName = this.pointStatesBefore.colorType
+                e.material.activeAttributeName = this.pointStatesBefore.colorType.get(e)
                 e.changePointOpacity(this.pointStatesBefore.opacity.get(e)) 
                 e.material.shape = this.pointStatesBefore.shape
                 
@@ -5709,8 +5710,8 @@ export class Viewer extends ViewerBase{
                      
                     boundingBox_.min.set( - radius, - radius, - radius );
                     boundingBox_.max.set( radius, radius, radius );
-               
-                     boundingBox_.translate(center)
+                    console.log('boundingVolume sphere',sphereData)
+                    boundingBox_.translate(center.negate())
                     
                     //2025:很少有模型用这个,之前是哪个模型有的?目前看到cesium的模型有 'http://192.168.0.25/oss/manage/media-library/result/test/tileset.json',
                     
@@ -5752,7 +5753,10 @@ export class Viewer extends ViewerBase{
                     
                     //获取在scale为1时,表现出的大小
                     boundingBox.union(boundingBox_.clone().applyMatrix4(child.matrixWorld)) //但感觉如果最外层object大小不为1,要还原下scale再乘
-                 
+                     
+                    if(child instanceof THREE.SkinnedMesh){ 
+                        child.boundingBox = null    //delete 动画会导致bound改变, raycast干脆不用boundingBox了,否则之后要实时重计算 
+                    } 
                     
                     let changeMat = (oldMat)=>{
                         let mat = oldMat
@@ -5942,7 +5946,8 @@ export class Viewer extends ViewerBase{
                     model.mixer = mixer
                 }
                 model.gltf = gltf
-                  
+                //model.traverse(e=>e.frustumCulled = false)  为什么有的动画模型离近了会消失,173ver的不会
+
                 
                 loadDone(model) 
             }, onProgress, onError)

+ 2 - 1
src/materials/shaders/depthBasic.fs

@@ -134,7 +134,8 @@ void main() {
             #endif
              
             #if defined(GL_EXT_frag_depth) && defined(useDepth)
-                color = vec4(mix(color.rgb, backColor, mixFactor), color.a * (1.0 - clipFactor));
+                float r = pow(1.0 - clipFactor, 3.0); //更透明些 
+                color = vec4(mix(color.rgb, backColor, mixFactor), color.a * r);
             #endif    
         }
          

+ 1 - 0
src/navigation/InputHandlerNew.js

@@ -942,6 +942,7 @@ export class InputHandler extends THREE.EventDispatcher {
             if(Potree.settings.intersectOnObjs && !dontIntersect){
                 if(point){
                     raycaster = new THREE.Raycaster() 
+                    raycaster.camera = camera
                     var dir = new THREE.Vector3().subVectors(point, camera.position).normalize()
                     raycaster.set(camera.position, dir) //var origin = new THREE.Vector3(pointer.x, pointer.y, -1).unproject(camera),
                 }  

+ 5 - 3
src/navigation/OrbitControlsNew.js

@@ -260,7 +260,9 @@ export class OrbitControls extends THREE.EventDispatcher{
                 let distance = o.position.distanceTo(o.CamTarget)
                 //if(distance < minRadius) minRadius = distance * 0.5 //融合页面当focus一个很小的物体时,需要将minRadius也调小
                 this.minRadius = Math.min(standartMinRadius, distance * 0.5)
-                //console.log('focus dis', distance) 
+                this.maxRadius = Math.max(this.maxRadius, distance)
+                
+                //console.log('focusOnObject radius ',  viewer.mainViewport.view.radius) 
             }
         })
          
@@ -330,12 +332,12 @@ export class OrbitControls extends THREE.EventDispatcher{
         let distance = THREE.Math.clamp(dis, 0.8 * object.scale.x , Math.max(len * 0.1 , 3 * object.scale.x) );
         this.minRadius = Math.min(distance, standartMinRadius) 
         this.maxRadius = dis * 2 
-        //console.log('maxRadius hasIntersect',   this.maxRadius)
+        //console.log('maxRadius hasIntersect', this.maxRadius)
         return distance
     }
     
     updateRadius(type){
-        if(type == 'startPan'){//以drag的point为target, 使drag跟手
+        if(type == 'startPan'){//以drag的point为target, 使drag跟手.     (如果scroll地面的时候也能改radius就好了,但是在朝模型scroll时容易误触地板导致radius突然增大)
             let I = viewer.inputHandler.intersect?.location
             if(!I){
                 let {x,y} = Potree.Utils.getPointerPosAtHeight(0, viewer.inputHandler.pointer ) 

+ 2 - 2
src/utils/VolumeNew.js

@@ -35,7 +35,7 @@ export class Volume extends THREE.Object3D {
 		this._modifiable = args.modifiable || true;
 
 	 
-		{ // event listeners
+		if(!args.noPointerEvent){ // event listeners
 			this.addEventListener('select', e => {
                 //console.log('select')
                 this.setSelected(true)   
@@ -193,7 +193,7 @@ export class BoxVolume extends Volume{
 		//this.frame = new THREE.LineSegments(boxFrameGeometry, new THREE.LineBasicMaterial({color: colors[this.clipTask], opacity:LineOpacity.default/* 0xff2050 */}));
 		this.frame = LineDraw.createFatLine(
                 boxFrameGeometry.vertices, 
-                { color: colors[this.clipTask], opacity:LineOpacity.default, lineWidth:1,  dontAlwaysSeen:true}   )
+                { color: colors[this.clipTask], opacity:LineOpacity.default, lineWidth:1,  dontAlwaysSeen:true, autoDepthTest:true}   )
                       
         // this.frame.mode = THREE.Lines;
 		this.add(this.frame);

+ 2 - 1
src/viewer/EDLRendererNew.js

@@ -259,7 +259,8 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
                     if(Potree.settings.fastTran && viewer.images360.fastTranMaskPass.enabled){
                         viewer.images360.fastTranMaskPass.render()
                     } 
-                    if( viewer.objs.children.length == 0 || !params.useModelOnRT  ) return //没有模型需要绘制遮挡
+                    //if( viewer.objs.children.length == 0 || !params.useModelOnRT  ) return //没有模型需要绘制遮挡
+                    if(viewer.objs.children.filter(e=>!e.is4dkkModel && e.visible).length == 0)return //需要绘制遮挡的小物体(layers为model)的个数为0    
                 }
                  
                  

+ 2 - 2
src/viewer/ExtendScene.js

@@ -11,7 +11,7 @@ class ExtendScene extends Scene{
 		super();
 
 		delete this.sceneBG;
-		this.overlayScene = new THREE.Scene();
+		this.overlayScene = new THREE.Scene();   this.overlayScene.name = 'overlay'
         viewer.addEventListener("render.pass.perspective_overlay", this.renderOverlay.bind(this)); 
 		
         
@@ -212,7 +212,7 @@ class ExtendScene extends Scene{
     
 
     renderOverlay(o={}){//  measure  tag
-        if(this.overlayScene.children.filter(e=>e.visible).length == 0)return
+        if(this.overlayScene.children.filter(e=>e.visible).length == 0 || o.viewport?.cameraLayers?.length && !o.viewport.cameraLayers.includes('sceneObjects'))return
         let renderer = o.renderer || this.viewer.renderer
         Potree.Utils.setCameraLayers(o.camera, ['sceneObjects'])
 		 

+ 1 - 1
src/viewer/ExtendView.js

@@ -262,7 +262,7 @@ class ExtendView extends View {
                 endQuaternion = info.quaternion.clone()
             }   
             
-            if(endQuaternion && math.closeTo(Math.abs(this.direction.z), 1, 1e-4)){ //在垂直的视角下的quaternion刚开始突变的厉害,这时候可能渐变yaw比较好(如俯视时点击测量线)
+            if(this.rotMode != 'free' && endQuaternion && math.closeTo(Math.abs(this.direction.z), 1, 1e-4)){ //在垂直的视角下的quaternion刚开始突变的厉害,这时候可能渐变yaw比较好(如俯视时点击测量线)
                 let a = this.clone();
                 a.quaternion = endQuaternion;
                 info.endYaw = a.yaw; info.endPitch = a.pitch;

+ 9 - 6
src/workers/BinaryDecoderWorker.js

@@ -1,9 +1,12 @@
 
-import * as THREE from "../../libs/three.js/build/three.module.js";
+
 import {Version} from "../Version.js";
 import {PointAttributes, PointAttribute, PointAttributeTypes} from "../loader/PointAttributes.js";
 
-import {Splat} from '../custom/objects/3dgs/Splat.js'
+/* import {Splat} from '../custom/objects/3dgs/Splat.js'  //暂时用不到
+ import {MathUtils,Vector3,Quaternion} from "../../libs/three.js/build/three.module.js"; 
+引用THREE的任何东西过来都会在打包时把THREE.js压缩进去,导致文件过大。所以是否要在此重写用到的类*/
+
 
 const typedArrayMapping = {
 	"int8":   Int8Array,
@@ -321,11 +324,11 @@ onmessage = function (event) {
             const offset_col = gs3dProplist.indexOf('f_dc_0')   
             let getColor = (index)=>{
                 let value = (0.5 + SH_C0 * f32[index+offset_col]) * 255;  
-                return THREE.Math.clamp(Math.floor(value), 0, 255);
+                return MathUtils.clamp(Math.floor(value), 0, 255);
             }
             let getOpacity = (index)=>{
                 let value = (1 / (1 + Math.exp(-f32[index+offset_opa]))) * 255;   
-                return THREE.Math.clamp(Math.floor(value), 0, 255);
+                return THREE.MathUtils.clamp(Math.floor(value), 0, 255);
             }
 			for (let j = 0; j < numPoints; j++) {
 				colors[4 * j + 0] = getColor(j * pointAttribute.numElements + 0)   
@@ -342,8 +345,8 @@ onmessage = function (event) {
             let covs = new Float32Array(buff3);
             const offset_scale = gs3dProplist.indexOf('scale_0') //第49个数开始是      
             const offset_rot = gs3dProplist.indexOf('rot_0')    
-            let scale = new THREE.Vector3()
-            let quaternion = new THREE.Quaternion()
+            let scale = new Vector3()
+            let quaternion = new Quaternion()
             
             let getScale = (index)=>{ 
                 let get = (offset)=>{