xzw недель назад: 3
Родитель
Сommit
8a3ca9c209

+ 125 - 52
examples/splatter.html

@@ -19,13 +19,31 @@
       height: 130px;
       position: absolute;
       right: 0px;
-      bottom: 2px;
+      bottom: 45px;
       z-index: 999999;
       color: "321";
       opacity: 0.9;
         font-size: 10px;
         
     }
+    #move_Btns{
+        position: fixed;
+        bottom: 10px;
+        width: 60px;
+        left: 3px;
+        height: 200px;
+        z-index: 90;
+        display: grid;
+    }
+    #move_Btns>button{
+        transform: rotate(90deg);
+        position: relative; 
+        font-size: 29px;
+        user-select: none;
+    }
+    #move_Btns span{
+        pointer-events:none;
+    }
 </style>
 <body>
 	<script src="../../libs/jquery/jquery-3.1.1.min.js"></script>
@@ -50,6 +68,12 @@
 		</div>
 		<div id="potree_sidebar_container"> </div>
 	</div>
+    <div id='move_Btns'  >
+        <button name='forward2' > <span><<</span></button>
+        <button name='forward' > <span><</span></button>
+        <button name='backward' ><span>></span></button>
+        <button name='backward2' ><span>>></span></button>
+    </div>
     <!-- <script src="https://webapi.amap.com/maps?v=2.0&key=4578048f6e03386759d5609401e738d3"></script> -->
 	<script type="module">
 
@@ -58,38 +82,84 @@
     window.THREE = THREE 
    
     Potree.config.view.near = 0.001,  Potree.config.view.far = 1e3  //same as splatter  
+    if(browser.isMobile()){
+        //window.addEventListener("load", ()=>{
+            var textarea = document.createElement('textarea');
+            textarea.id = "consoleLog";
+
+            document.getElementsByTagName("body")[0].appendChild(textarea);
+            var list = ["log", "error", "warn", "debug", "info", "time", "timeEnd"]
+            var exchange = function (o) {
+                console["old" + o] = console[o];
+                console[o] = function () {
+                    console["old" + o].apply(this, arguments)
+                    let str = ''
+                    for(let i=0;i<arguments.length;i++){
+                        str += arguments[i] + ' '
+                    }
+                    textarea.innerHTML = str + "\n\n" + textarea.innerHTML;
+                }
+            }
+
+            for (var i = 0; i < list.length; i++) {
+                exchange(list[i])
+            }  
+             
+        //}) 
+        
+        {
+            
+            let btns = document.querySelector('#move_Btns')    
+            Array.from(btns.children).forEach((e,i)=>{
+                let name = i<2 ? 'FORWARD' : 'BACKWARD'  
+                let f = (ev)=>{
+                    ev.preventDefault()
+                     ev.stopPropagation()
+                    viewer.inputHandler.pressedKeys[viewer.controls.keys['FORWARD'][0]] = 0
+                    viewer.inputHandler.pressedKeys[viewer.controls.keys['BACKWARD'][0]] = 0
+                }
+                let pointerdown = (ev)=>{
+                    f(ev)
+                    viewer.inputHandler.pressedKeys[viewer.controls.keys[name][0]] = 1;
+                     (i==1||i==2) && (viewer.inputHandler.pressedKeys[viewer.controls.keys['ALT'][0]] = 1)
+                    //viewer.inputHandler.pressedKeys[viewer.controls.keys['SPACE'][0]] = 1
+                    
+                }
+                let pointerup = (ev)=>{
+                    f(ev) 
+                    viewer.inputHandler.pressedKeys[viewer.controls.keys['ALT'][0]] = 0
+                    //viewer.inputHandler.pressedKeys[viewer.controls.keys['SPACE'][0]] = 0
+                }
+                e.addEventListener('pointerdown',pointerdown)
+                e.addEventListener('pointerup', pointerup)
+                e.addEventListener('pointerout', pointerup)
+            })  
+            
+            document.addEventListener('contextmenu', function(e) {
+                if (e.target.classList.contains('no-context-menu')) {
+                    e.preventDefault();
+                }
+            });
+        }
+        
+    }
     
     var splatId = browser.urlHasValue('m',true)  
     var urlAtSplatter = !browser.urlHasValue('urlAtCurrent') ; 
     //Potree.start(document.getElementById("potree_render_area"),null, null,{noMap:true}); 
     new Potree.Viewer(document.getElementById("potree_render_area") , null, {noMap:true});
     viewer.background.set('#000')
-    
+    Potree.settings.orbitCtlMoveFree = true
     
     if(splatId === ''){
         splatId = 'SG-t-jp-zSUztbgFpmt', urlAtSplatter = true
     }
-    /*const defaultConfig = {
-        "splatId": 'SG-t-jp-zSUztbgFpmt', // "test0_4096_L8_not_sortscale", 
-        "block": 65536, 
-        "root": {
-            "radius": 0.6,//0.4,//  1.024,
-            "size": 35031//8326 //8534
-        },
-        "size": 649*65536,  //421*
-        "tile": 4,  
-        path: Potree.resourcePath+'../../../../examples/tomcat/splatter.app/data',
-        view:{
-            "yaw": -1.5924752534051696,
-            "pitch": -0.14400671146230742,
-            "position": {
-                "x": -45.12437783490361,
-                "y": 1.6148221490172163,
-                "z": 2.9891692740919122
-            }
+   
+    let localProfile = {
+        'SG-t-WSs5eaQJLoc' :{
+            view : {"yaw":-1.6062499999999997,"pitch":0.13850996852046182,"position":{"x":-42.06086329177142,"y":3.3968851133538633,"z":-1.9854159672413823}}
         }
-    }  */
-    
+    }[splatId]
     
     
     
@@ -120,9 +190,7 @@
         let dataVersion = path.includes('http') ? Date.now() : 10
         let jsonUrl = Potree.Common.joinUrl(path, 'data.json?m='+dataVersion)
         Potree.loadFile(jsonUrl,{},(e)=>{ 
-            let config = Object.assign({
-                
-            }, e, {
+            let config = Object.assign(  e, localProfile, {
                 "block": 65536, 
                 "root": {
                     "radius": browser.urlHasValue('radius', true) || e.radius || (browser.isMobile() ? 0.25 : 0.6),    
@@ -135,44 +203,49 @@
             })  
         
             applyConfig(config)
+            
+            let btn1 = document.querySelector('#potree_render_area [value=">>全景"]')
+            btn1.value = '停lod'
+            btn1.onclick = ()=>{ 
+                btn1.value = btn1.value == '停lod' ? '开lod' : '停lod' 
+                viewer.splatter.renderer.lodder.pauseLod = btn1.value == '停lod' ? 0 : 1
+            }
+            let btn2 = document.querySelector('#potree_render_area [value="隐藏点云"]')
+            btn2.value = '停sort' 
+            btn2.onclick = ()=>{
+                btn2.value = btn2.value == '停sort' ? '开sort' : '停sort' 
+                viewer.splatter.renderer.lodder.pauseSort = btn2.value == '停sort' ? 0 : 1
+            }
+            
+            
         })
     
     
     } 
      
-     
+    Potree.settings.rotAroundPoint = false  
      
     viewer.scene.axisArrow.visible = true  
     //example: https://192.168.0.59:1234/examples/splatter.html?m=rly-jb1  
-     
-    //viewer.setFOV(50) //splatter原本中设置最小fov为50
-    viewer.setFOV(75) //原本70,在手机端比splatter的点多,增大fov会减少点
+    Potree.config.view.fov = 50  
+    Potree.settings.keepMinFov = true 
+    viewer.setFOV(50)//原本70,在手机端比splatter的点多,增大fov会减少点
     Potree.settings.intersectWhenHover = false   //降cpu
     //viewer.scene.axisArrow.visible = true // 会导致效果不对还警告?!!!!
     
-    
-    
-    if(browser.isMobile()){
-        window.addEventListener("load", ()=>{
-            var textarea = document.createElement('textarea');
-            textarea.id = "consoleLog";
-
-            document.getElementsByTagName("body")[0].appendChild(textarea);
-            var list = ["log", "error", "warn", "debug", "info", "time", "timeEnd"]
-            var exchange = function (o) {
-                console["old" + o] = console[o];
-                console[o] = function (str ) {
-                    console["old" + o].apply(this, arguments)
-                    textarea.innerHTML = str + "\n\n" + textarea.innerHTML;
-                }
-            }
-
-            for (var i = 0; i < list.length; i++) {
-                exchange(list[i])
-            }  
-         
-        }) 
-    }
+     setTimeout(()=>{
+         //console.log('stop lod and sort!  ')
+        //viewer.splatter.renderer.lodder.pauseLod = 1
+        //viewer.splatter.renderer.lodder.pauseSort = 1
+        
+        //viewer.setControls(viewer.orbitControls)
+        
+        
+      //  setInterval(()=>{
+      //      viewer.controls.yawDelta -= 0.002
+      //  },8)
+        
+    },48200)  
     
 	</script>
 	

+ 1 - 0
src/custom/modules/panos/Images360.js

@@ -244,6 +244,7 @@ export class Images360 extends THREE.EventDispatcher{
                 }) 
                 this.domRoot.appendChild(elHide[0]);
                 elHide.on("click", (e) => { 
+                    if(!viewer.scene.pointclouds[0])return
                     let visi = Potree.Utils.getObjVisiByReason(viewer.scene.pointclouds[0], 'force')
                     viewer.scene.pointclouds.forEach(e=>{ 
                         Potree.Utils.updateVisible(e, 'force', !visi) 

+ 1 - 1
src/custom/modules/panos/tile/TileDownloader.js

@@ -128,7 +128,7 @@ class TileDownloader extends THREE.EventDispatcher{
         }
   
         
-        let time2 = 1000//Potree.Common.getBestCountFPS('filterDepthTex',  false,  5000, 88, 2, 63  ) 
+        let time2 = Potree.settings.displayMode == 'showPanos' ? 1000 : 8000 //Potree.Common.getBestCountFPS('filterDepthTex',  false,  5000, 88, 2, 63  ) 
         Potree.Common.intervalTool.isWaiting('filterDepthTex', ()=>{  
             this.tilePrioritizer.filterDepthTex(this.panos)//下载深度图
         }, time2)

+ 196 - 89
src/custom/objects/3dgs/splatter/SplatterThree.js

@@ -116,7 +116,7 @@ function saveGLState(A) {
      
     return g;
 }
-function resetGLState(A) {
+function resetGLState(A, clear) {
     
     A.disable(A.BLEND),
     A.disable(A.CULL_FACE),//
@@ -124,9 +124,11 @@ function resetGLState(A) {
     A.disable(A.POLYGON_OFFSET_FILL),
     A.disable(A.SCISSOR_TEST),
     A.disable(A.STENCIL_TEST),
-    A.disable(A.SAMPLE_ALPHA_TO_COVERAGE),
-    // A.colorMask(true, true, true, true),
-    //A.clearColor(0, 0, 0, 0),
+    A.disable(A.SAMPLE_ALPHA_TO_COVERAGE) 
+    /* if(clear){
+        A.colorMask(true, true, true, true)
+        A.clearColor(0, 0, 0, 0)
+    }  */ 
     A.depthMask(true),
     A.depthFunc(A.LESS) 
     A.clearDepth(1),
@@ -1442,19 +1444,19 @@ var Lodder = class {
         ))
     }
     
-    lod(camera, width) {
-        if(!this.worker.working ){
+    lod(camera, width, scale=1) {
+        if(!this.worker.working && !this.pauseLod){
             if(distanceSq(camera.eye, this.eye2) > .001 || distanceSq(camera.look, this.look2) > .001 || this.version != this.sortVersion){
                 this.worker.working = !0  
                  
-                /* console.log('lod', Date.now() - lastLodTime), 
+                /*  console.log('lod', Date.now() - lastLodTime), 
                 lastLodTime = Date.now(),
-                 */ 
+                  */
                 this.send("lod", { 
                     eye: camera.eye,
                     look: camera.look,
                     center: camera.center,
-                    focal: camera.projMat[0] * width / 2 / window.devicePixelRatio, //改:原版的canvas.width没有乘以dpr,是比较模糊的,所以我在这除以dpr,否则手机点数太多,
+                    focal: camera.projMat[0] * width / 2 / scale /* viewer.splatter.scale *//* window.devicePixelRatio */, //改:原版的canvas.width没有乘以dpr,是比较模糊的,所以我在这除以dpr,否则手机点数太多,
                     detail: this.detail,
                     fov: camera.getMaxFov()
                 }),//focal和hfov有关  大一点似乎点数少一些
@@ -1471,7 +1473,7 @@ var Lodder = class {
     }
     
     sort(A, g, I) {
-        if (!this.worker.working) {
+        if (!this.worker.working && !this.pauseSort) {
             if (!(distanceSq(A.eye, this.eye3) > .001))
                 return !1;
             this.worker.working = !0,
@@ -1491,6 +1493,12 @@ var Lodder = class {
         this.update(),
         console.log(`Detail: ${this.detail}`)
     }
+    setDetail2(A) {  
+        this.detail = A,
+        this.version++,
+        this.update()  
+    }
+    
     receiveBlock(fileName, cacheIndex, I) {
         //console.log('receiveBlock', 'index', fileName, 'page', cacheIndex) 
         
@@ -1799,10 +1807,19 @@ class Renderer {
         lastRender = Date.now()  
          */
         
-        if (this.options.sort && (this.sort(A) || this.lodder.lod(A, width)),
-        this.upload(),
-        this.ifUpdateShader(),
-        !(this.gauss1 && this.gauss2 && this.gauss3 && this.bufferUsing.size))
+        if(this.options.sort){
+            
+            //Potree.Common.intervalTool.isWaiting('lodAndSort', () => {
+                this.sort(A) || this.lodder.lod(A, width, this.splatter.scale)
+	        //}, 1000); 
+            
+        } 
+    
+        
+        
+        this.upload()
+        this.ifUpdateShader()
+        if (!(this.gauss1 && this.gauss2 && this.gauss3 && this.bufferUsing.size))
             return;
         let B = this.gl;
         B.bindVertexArray(this.vao),
@@ -1811,10 +1828,29 @@ class Renderer {
         B.blendFunc(B.ONE, B.ONE_MINUS_SRC_ALPHA),
         this.draw(A, this.shader_noDepth, width, height),
         B.bindVertexArray(null)
+         
     }
     
     
-    
+    renderDepth1(A, w, h ) {
+        if (this.ifUpdateShader(),
+        !(this.gauss1 && this.gauss2 && this.gauss3 && this.bufferUsing.size))
+            return;
+        let B = this.gl;
+        B.bindVertexArray(this.vao)
+       
+        B.viewport(0, 0, w, h ),
+        B.clearColor(1, 1, 1, 1),
+         
+        viewer.renderer.setClearColor( 0xffffff, 1)//B.clearColor(1, 1, 1, 1), 
+        B.clear(B.COLOR_BUFFER_BIT),
+        B.disable(B.BLEND),
+        B.disable(B.DEPTH_TEST),
+        this.draw(A, this.shader_depth, w, h),
+        B.bindVertexArray(null)
+          
+        
+    }
     renderDepth(A, w, h, x, y) {
         if (this.ifUpdateShader(),
         !(this.gauss1 && this.gauss2 && this.gauss3 && this.bufferUsing.size))
@@ -1842,27 +1878,27 @@ class Renderer {
         B.disable(B.SCISSOR_TEST) //add
         
     }
-    /* sg(A, g) {
+     sg(A, g) {//hitTest for  用controls时
         let I = this.gl
           , [B,E] = [I.canvas.width / 2, I.canvas.height / 2]
           , i = new Framebuffer(I,B,E);
-        i.O(I.COLOR_ATTACHMENT0, I.RGBA, I.RGBA, I.UNSIGNED_BYTE),
-        i.T(),
+        i.set(I.COLOR_ATTACHMENT0, I.RGBA, I.RGBA, I.UNSIGNED_BYTE),
+        i.check(),
         i.bind(),
-        this.renderDepth(A, B, E);
+        this.renderDepth1(A, B, E);
         let o = new Uint8Array(4)
           , D = [];
         for (let[A,C] of g) {
             let[g,i] = [Math.round(A * B), Math.round(C * E)];
             I.readPixels(g, i, 1, 1, I.RGBA, I.UNSIGNED_BYTE, o);
-            let w = Q(...o)
+            let w = decodeFloatRGB(...o)
               , t = Math.exp(12 * w) - 1;
             D.push(t < 1e5 ? t : null)
         }
-        return i.l(),
+        return i.unbind(),
         i.delete(),
         D
-    } */
+    }  
     
     getDepth(camera, mouseArr) { //在这只会有一个mouse
         let I = this.gl
@@ -2122,9 +2158,9 @@ class Renderer {
         }
     }
 }
- /*  let W = 1e-5
+ let W = 1e-5
   , p = 9e4
-  , X = class {
+  , Controls = class {
     constructor(A, g=[0, -1, 0]) {
         this.center = Vec3(),
         this.Mg = 0,
@@ -2172,7 +2208,7 @@ class Renderer {
                 Xg: !1
             },
             this.ng = Vec3();
-            let g = document.getElementById("fly-button");
+            /* let g = document.getElementById("fly-button");
             g && (g.addEventListener("pointerdown", this.mg.bind(this)),
             g.addEventListener("pointerup", this.Zg.bind(this)),
             g.addEventListener("pointermove", this.Vg.bind(this)),
@@ -2181,12 +2217,12 @@ class Renderer {
             }
             )),
             g.addEventListener("click", ( () => {}
-            ))),
-            this.Pg = g,
+            ))), 
+            this.Pg = g,*/
             this.vg = !1,
             this.bg = 0,
             this.zg = 1,
-            this.isMobile || (document.getElementById("fly-button-container").style.display = "none"),
+            //this.isMobile || (document.getElementById("fly-button-container").style.display = "none"),
             this._g(),
             this.$g()
         }
@@ -2315,8 +2351,8 @@ class Renderer {
     AI() {
         let A = applyMat4ToVec3(inverse([...this.right, 0, ...this.forward, 0, ...this.up, 0, ...this.center, 1]), this.eye);
         this.radius = distance(this.eye, this.center),
-        this.Mg = i(Math.atan2(A[1], A[0])),
-        this.eg = i(Math.asin(A[2] / this.radius))
+        this.Mg = radToDeg(Math.atan2(A[1], A[0])),
+        this.eg = radToDeg(Math.asin(A[2] / this.radius))
     }
     oI() {
         let A = normalize(h(this.center, this.eye))
@@ -2534,10 +2570,11 @@ class Renderer {
         this.Pg.style.transform = ""
     }
     wI() {
+        return
         this.Pg.style.visibility = this.Og && !this.iI() ? "hidden" : "visible"
     }
 }  
-  , m = 1e-6
+ /* , m = 1e-6
     , Z = class {
     constructor(A, g) {
         let I = new URLSearchParams(document.location.search).has("configure");
@@ -2693,29 +2730,43 @@ export class Splatter extends THREE.EventDispatcher{
         this.worldMat = identity(),
         this.modelViewMat = identity(),
         this.states = {} 
-        
-        
+     
         
         this.renderer = new Renderer(this.gl,this.dataset,this), 
         //this.renderer.onupdate = this.update.bind(this),
         this.renderer.onupdate = () => {
             this.dispatchEvent("update");
         }
-    
-        //add
-        this.position = new THREE.Vector3()
-        this.rotationZ = 0
-        this.originRotMat = new THREE.Matrix4()
-        if(info.originGsData && info.rotateX){
-            this.originRotMat.makeRotationX(info.rotateX) //add
-            this.setTransform(this.originRotMat);
-        }
-        if(info.position){
-            this.setPosition(info.position)
+       // this.kI = document.timeline.currentTime 
+        /* this.controls = new Controls( viewer.renderer.domElement ),
+        this.controls.onupdate = this.update.bind(this),
+        this.controls.Sg = this.rA.bind(this) */
+        if(this.controls){
+            this.dataset.ready.then(( () => {
+                this.controls.setUp(this.dataset.upDirection),
+                //this.nI.position ? this.JI(this.nI.position) : this.controls.NA(this.dataset.defaultView),
+                this.controls.EI(),
+                //setInterval(this.KI.bind(this), 200),
+                //this.renderer.Cg(this.dataset.backgroundColor),
+                this.controls.ug = performance.now(),
+                this.update()
+            } )) 
+        }else{
+            //add
+            this.position = new THREE.Vector3()
+            this.rotationZ = 0
+            this.originRotMat = new THREE.Matrix4()
+            if(info.originGsData && info.rotateX){
+                this.originRotMat.makeRotationX(info.rotateX) //add
+                this.setTransform(this.originRotMat);
+            }
+            if(info.position){
+                this.setPosition(info.position)
+            }
+            if(info.rotateZ){
+                this.setRotateZ(info.rotateZ)
+            }  
         }
-        if(info.rotateZ){
-            this.setRotateZ(info.rotateZ)
-        }   
         viewer.inputHandler.addEventListener('keydown', (e)=>{
             //if(e.target)
             let key = e.event.key.toLowerCase()  
@@ -2725,39 +2776,59 @@ export class Splatter extends THREE.EventDispatcher{
                 this.renderer.lodder.setDetail(1);
             }   
         }) 
-             
-             
-        /* this.controls = new X(this.canvas),
-        this.controls.onupdate = this.update.bind(this),
-        this.controls.Sg = this.rA.bind(this),
+        let detail = browser.urlHasValue('gsDetail',true)      
+        detail && this.renderer.lodder.setDetail2(parseFloat(detail)); 
+        
+        
+        /* 
         this.LI = new Z(this,this.canvas), */
         /* window.addEventListener("resize", this.update.bind(this)),
         document.addEventListener("keyup", this.HI.bind(this)),
-        this.dataset.ready.then(( () => {
-            this.controls.setUp(this.dataset.upDirection),
-            this.nI.position ? this.JI(this.nI.position) : this.controls.NA(this.dataset.defaultView),
-            this.controls.EI(),
-            setInterval(this.KI.bind(this), 200),
-            this.renderer.Cg(this.dataset.backgroundColor),
-            this.controls.ug = performance.now(),
-            this.update()
-        } )), */
-        this.kI = document.timeline.currentTime,
-        this.fI = !1,
-        //this.update()
+        */
+        
+        this.needRender = !1 
+        
         //-----------
         
         
         this.visible_ = true
+        //this.renderType2 = true
+        
         //this.bound = new THREE.Box3()
-        viewer.addEventListener('render.end', ()=>{
-            if(!this.visible)return
-            this.render(viewer.mainViewport.camera/* , viewer.mainViewport.view.getPivot() */);
-        }) 
         
-        this.addEventListener('update', ()=>{ 
-            viewer.dispatchEvent('content_changed')//触发渲染
-        });
+        if( this.controls  ){
+            viewer.paused = 1
+            viewer.addEventListener('loopStart1',(e)=>{
+                if(this.needRender){ 
+                    this.render(viewer.mainViewport.camera, e.delta)
+                }
+            })
+            viewer.addEventListener('camera_changed', e => {
+                this.update()
+            }); 
+            
+        }else if(this.renderType2){
+            viewer.pauseRender = true
+            viewer.addEventListener('loopStart',(e)=>{
+                if(this.needRender){
+                    this.render(viewer.mainViewport.camera, e.delta)
+                }
+            })
+            viewer.addEventListener('camera_changed', e => {
+                this.update()
+            }); 
+             
+        
+        }else{
+            viewer.addEventListener('render.end', (e)=>{
+                if(!this.visible /* || e.viewport?.name != 'MainView' */)return
+                this.render(viewer.mainViewport.camera/* , viewer.mainViewport.view.getPivot() */);
+            }) 
+            
+            this.addEventListener('update', ()=>{ 
+                viewer.dispatchEvent('content_changed')//触发渲染
+            });
+        }
         viewer.splatter = this
     }
     
@@ -2780,7 +2851,7 @@ export class Splatter extends THREE.EventDispatcher{
         let g = this.gl
           , I = A - this.kI;
         this.kI = A,
-        this.fI = !1,
+        this.needRender = !1,
         //this.controls.animate(I);
         //let B = this.resize();
         this.camera.aA(B),
@@ -2794,44 +2865,77 @@ export class Splatter extends THREE.EventDispatcher{
         this.update())
     } */
     transCamera(threeCamera, target=null) { //transCamera
+    
+        //////////////////// */
         multiply(threeCamera.matrixWorldInverse.elements, this.worldMat, this.modelViewMat),
         this.camera.applyThreeCam(this.modelViewMat, threeCamera.projectionMatrix.elements),
         target && (this.camera.center[0] = target.x,
         this.camera.center[1] = target.y,
         this.camera.center[2] = target.z);
     }
-    render(threeCamera, target=null) {
+    render(threeCamera, delta ) {
+        viewer.addTimeMark('renderGS','start') 
+        //this.controls.animate(I);
+        //let B = this.resize();
+        let B = this.resize(); //根据scale 重设宽高,手机降分辨率
         let I = this.gl;
-        this.saveState(),
-        this.transCamera(threeCamera, target),
+        this.saveState()
+        if(this.controls){
+            this.controls.animate(delta * 1000);
+            this.camera.aA(threeCamera.aspect),
+            this.camera.NA(this.controls.smooth.eye, this.controls.smooth.center, this.controls.up),
+            this.needRender = !1
+            I.clear(I.COLOR_BUFFER_BIT)    
+
+            let C = 5 - (performance.now() - this.controls.ug) / 300;
+            C > 0 && (/* this.renderer.draw(this.camera, this.controls.center, 32 * this.scale, C, this.controls.iI() ? 1 : 0), */
+            this.update())
+        }else{ 
+            if(this.renderType2){
+                
+                let view = viewer.mainViewport.view
+                
+                this.camera.aA(B) ;
+                //this.camera.aA(threeCamera.aspect);
+                this.camera.NA(view.position.toArray(), view.getPivot().toArray(), this.dataset.upDirection)
+                I.clear(I.COLOR_BUFFER_BIT)    
+                this.needRender = !1
+            }else{
+                this.transCamera(threeCamera/* , target */)   
+            }
+        }
+        
+        
         I.enable(I.DEPTH_TEST),
         I.depthMask(false),
         this.renderer.render(this.camera, I.canvas.width, I.canvas.height),
         this.restoreState();
+         viewer.addTimeMark('renderGS','end') 
     }  
     
     
+    rA(A, g) {  
+        let[I,B] = [A * this.scale / this.gl.canvas.width, 1 - g * this.scale / this.gl.canvas.height]
+          , C = this.renderer.sg(this.camera, [[I, B]]);
+        return null !== C[0] ? this.camera.getPos3d(I, B, C[0]) : null
+    }  
+    update() {
+        //this.needRender|| (requestAnimationFrame(this.render.bind(this)),
+        this.needRender = !0//)   
+        //this.dispatchEvent("update");
+    }
     
     
     
-    
-    /* update() {
-        this.fI || (requestAnimationFrame(this.render.bind(this)),
-        this.fI = !0)
-    }
-    resize() {
-        let A = this.canvas
+    resize() { 
+        let A = viewer.renderer.domElement
           , g = Math.round(A.clientWidth * this.scale)
           , I = Math.round(A.clientHeight * this.scale);
         return A.width == g && A.height == I || (A.width = g,
         A.height = I),
         g / I
     } 
-     rA(A, g) {
-        let[I,B] = [A * this.scale / this.gl.canvas.width, 1 - g * this.scale / this.gl.canvas.height]
-          , C = this.renderer.sg(this.camera, [[I, B]]);
-        return null !== C[0] ? this.camera.rA(I, B, C[0]) : null
-    }  
+    /*
     lI() {
         let A = this.controls
           , g = [A.center[0], A.center[1], A.center[2], A.Mg - 90, A.eg, Math.log2(A.radius)]
@@ -2949,10 +3053,11 @@ export class Splatter extends THREE.EventDispatcher{
         let A = this.gl;
         /* this.states.GL = saveGLState(A),
         this.states.Texture = saveTextureState(A)  */
-        resetGLState(A);
+        resetGLState(A );
         //viewer.addTimeMark('saveState','end')
     }
     restoreState() {//restoreState 
+        if(this.renderType2 || this.controls)    return
         let A = this.gl;
         //restoreTextureState(A, this.states.Texture); 
         restoreGLState(A, this.states.GL)  
@@ -2984,6 +3089,8 @@ export class Splatter extends THREE.EventDispatcher{
         this.setTransform(mat)
     }
     hitTest(threeCamera, mouse, I) {
+        if(browser.urlHasValue('stopHit'))return
+        
         viewer.addTimeMark('hitTest', 'start')
         console.log('hitTest', Date.now() - lastHit),
         lastHit = Date.now()
@@ -2998,7 +3105,7 @@ export class Splatter extends THREE.EventDispatcher{
             mouses.push([A2[0] / this.gl.canvas.clientWidth, 1 - A2[1] / this.gl.canvas.clientHeight]);
         }
         this.saveState(),
-        this.transCamera(threeCamera),
+        (this.renderType2 || this.controls) || this.transCamera(threeCamera),
         this.renderer.options.alphaThreshold = (I == null ? void 0 : I.alphaThreshold) ?? 0.25;
         let depths = this.renderer.getDepth(this.camera, mouses);
         this.restoreState();   

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

@@ -186,7 +186,7 @@ export default class AxisViewer extends ViewerBase{
         
         
     render(){
-        viewer.dispatchEvent({type:"render.begin", viewport:this.viewports[0]}) //update sprite
+        viewer.dispatchEvent({type:"render.begin", viewport:this.viewports[0], viewer:this}) //update sprite
         this.renderer.render(this.scene, this.camera)
     }
         

+ 37 - 47
src/custom/objects/tool/Measure.js

@@ -119,8 +119,7 @@ export class Measure extends ctrlPolygon{
         //Potree.Utils.setObjectLayers(this, 'measure' ) //取消:scene单独渲染应该不需要设置layer
         
         
-        if(this.measureType == 'MulDistance' || this.measureType == 'Hor MulDistance' || this.measureType == 'Ver MulDistance'){
-            //this.showTotalDis = true 
+        if(this.showTotalDis ){
             this.totalDisLabel = this.createTotalDisLabel()
             this.add(this.totalDisLabel) 
         }
@@ -167,7 +166,7 @@ export class Measure extends ctrlPolygon{
      
     updateDatasetBelong(changeIndex){//更新所属数据集
      
-        if(Potree.settings.editType == "merge" || this.measureType == 'MulDistance Ring'){//点直接跟着数据集走,不用找整体的datasetId
+        if(Potree.settings.editType == "merge" || this.measureType == 'MulDistance Ring' || this.noDatasetId){//点直接跟着数据集走,不用找整体的datasetId
           
             this.dataset_points[changeIndex] = Potree.Utils.datasetPosTransform({toDataset:true, datasetId:this.points_datasets[changeIndex], position:this.points[changeIndex].clone()})
              
@@ -738,7 +737,7 @@ export class Measure extends ctrlPolygon{
         super.addMarker(Object.assign(o, {index, marker,  edge}))
         
         
-		if(this.showEdges){ // edge labels  
+		if(this.showDistances/* showDistances */){ // edge labels  
             const edgeLabel = this.createEdgeLabel('edgeLabel', !this.closed)  
 			this.edgeLabels = [...this.edgeLabels.slice(0,index), edgeLabel, ...this.edgeLabels.slice(index,this.edgeLabels.length)]
 		 
@@ -1313,96 +1312,87 @@ export class Measure extends ctrlPolygon{
         return this.pointsPos2d.get(viewport) 
     }
     
-    transformData(prop){
-        if(prop.measureType == 'Point'){ 
+    transformData(prop_){
+        let prop = {}
+        if(prop_.measureType == 'Point'){ 
             prop.showCoordinates = true, 
             prop.closed = true, 
             prop.maxMarkers = 1,
             prop.minMarkers = 1 
-        }else if(prop.measureType == 'Distance'){
-            prop.showDistances = true,   
-            prop.showEdges = true,
+        }else if(prop_.measureType == 'Distance'){
+            prop.showDistances = true,    
             prop.maxMarkers = 2,
             prop.minMarkers = 2 
-        }else if(prop.measureType == 'MulDistance'){ 
-            prop.showDistances = true,  
-            prop.showEdges = true, 
+        }else if(prop_.measureType == 'MulDistance'){ 
+            prop.showDistances = true, 
+            prop.showTotalDis = true
             prop.minMarkers = 2 
-        }else if(prop.measureType == 'MulDistance Ring'){
-            prop.showDistances = true,  
-            prop.showEdges = true, 
+        }else if(prop_.measureType == 'MulDistance Ring'){
+            prop.showDistances = true,   
             prop.showArea = true,
             prop.closed = true, 
             prop.minMarkers = 3  
-        }else if(prop.measureType == 'Ver MulDistance'){ 
+        }else if(prop_.measureType == 'Ver MulDistance'){ 
             prop.showDistances = true,
-            prop.atPlane = true,                
-            prop.showEdges = true, 
+            prop.showTotalDis = true
+            prop.atPlane = true,           
             prop.minMarkers = 2 
             prop.faceDirection = "vertical" 
             prop.unableDragAtMap = true
-        }else if(prop.measureType == 'Hor MulDistance'){
+        }else if(prop_.measureType == 'Hor MulDistance'){
             prop.showDistances = true,
-            prop.atPlane = true,
-            prop.showEdges = true, 
+            prop.showTotalDis = true
+            prop.atPlane = true,  
             prop.minMarkers = 2 
             prop.faceDirection = "horizontal"  
-        }else if(prop.measureType == 'Ver Distance'){
-            prop.showDistances = true,  
-            prop.showEdges = true,
+        }else if(prop_.measureType == 'Ver Distance'){
+            prop.showDistances = true,   
             prop.maxMarkers = 2,
             prop.minMarkers = 2,
             prop.faceDirection = "vertical" 
             prop.unableDragAtMap = true
-        }else if(prop.measureType == 'Hor Distance'){
-            prop.showDistances = true, 
-            prop.showEdges = true,
+        }else if(prop_.measureType == 'Hor Distance'){
+            prop.showDistances = true,  
             prop.maxMarkers = 2,
             prop.minMarkers = 2,
             prop.faceDirection = "horizontal"  
                    
-        }else if(prop.measureType == 'Area'){
+        }else if(prop_.measureType == 'Area'){
             prop.showDistances = true,  
-            Potree.settings.areaAtNotPlane || (prop.atPlane = true)                
-            prop.showEdges = true,
+            Potree.settings.areaAtNotPlane || (prop.atPlane = true) 
             prop.closed = true, 
             prop.minMarkers = 3  
-        }else if(prop.measureType == 'Hor Area'){
+        }else if(prop_.measureType == 'Hor Area'){
             prop.showDistances = true,  
-            prop.atPlane = true,  
-            prop.showEdges = true,
+            prop.atPlane = true,   
             prop.closed = true, 
             prop.minMarkers = 3  
             prop.faceDirection = "horizontal"
              
-        }else if(prop.measureType == 'Ver Area'){
+        }else if(prop_.measureType == 'Ver Area'){
             prop.showDistances = true,  
-            prop.atPlane = true,  
-            prop.showEdges = true,
+            prop.atPlane = true,   
             prop.closed = true, 
             prop.minMarkers = 3 
             prop.faceDirection = "vertical"   
             prop.unableDragAtMap = true            
-        }else if(prop.measureType == 'Rect Area'){
+        }else if(prop_.measureType == 'Rect Area'){
             prop.showDistances = true,  
-            prop.atPlane = true,  
-            prop.showEdges = true,
+            prop.atPlane = true,   
             prop.closed = true, 
             prop.minMarkers = 4 
             prop.maxMarkers = 4            
-        }else if(prop.measureType == 'Hor Rect Area'){
+        }else if(prop_.measureType == 'Hor Rect Area'){
             prop.showDistances = true,  
-            prop.atPlane = true,  
-            prop.showEdges = true,
+            prop.atPlane = true,   
             prop.closed = true, 
             prop.minMarkers = 4 
             prop.maxMarkers = 4 
             prop.isRect = true 
             prop.faceDirection = "horizontal" 
-        }else if(prop.measureType == 'Ver Rect Area'){
+        }else if(prop_.measureType == 'Ver Rect Area'){
             prop.showDistances = true,  
-            prop.atPlane = true,  
-            prop.showEdges = true,
+            prop.atPlane = true,   
             prop.closed = true, 
             prop.minMarkers = 4 
             prop.maxMarkers = 4 
@@ -1413,11 +1403,11 @@ export class Measure extends ctrlPolygon{
         if(prop.atPlane && prop.closed){ //atPlane在同一平面上
             prop.showArea = true
         }
+        prop = Object.assign(prop, prop_)
         
         
-        super.transformData(prop)
-        
         
+        return  super.transformData(prop)
         
     }
 

+ 68 - 4
src/custom/objects/tool/MeasuringTool.js

@@ -120,10 +120,69 @@ export class MeasuringTool extends THREE.EventDispatcher{
 		e.scene.addEventListener('measurement_removed', this.onRemove);
 	}
 
-
-    
-
-
+   
+    analysePoints({data, dataset_points_name, points_datasets_name  }){
+        let newData = {}
+  
+        
+        let hasBranch = data.some(e=>e instanceof Array)//有分岔
+        newData.dataset_points = []
+        newData.points_datasets = []
+        
+        let nodes = []
+        
+        if(hasBranch){
+            newData.linkMap = new Array() //线信息。如 0:{1:0,2:1} 代表点0到点1之间为线0、到点2之间为线1
+            newData.lineCount = 0
+            
+            
+            let checkSame = (a,b)=>{
+                return Potree.Common.ifSame(a,b)//a.id == b.id
+            }
+            let addLink = (from,to)=>{
+                if(checkSame(from,to))return
+                if(newData.linkMap[from] == void 0) newData.linkMap[from] = {}
+                if(newData.linkMap[to] == void 0) newData.linkMap[to] = {}
+                newData.linkMap[from][to] = newData.lineCount
+                newData.linkMap[to][from] = newData.lineCount
+                newData.lineCount++ 
+            }
+            
+            let searchStart = (array, last)=>{//从一条数组开始找起
+             
+                array.forEach(node=>{ 
+                    if(node instanceof Array) return last = node.map(arr=>searchStart(arr, last)) //给并行的分岔传入当前最后点,并得到它们的最后点
+                    let cur = nodes.findIndex(e=>checkSame(e,node)) //当前点如果是重复点,用之前的index, 如 [ 'a', [['b'],['c'],['d']], 'd', 'e' ]  'd'出现两次
+                    cur == -1 && (cur = nodes.length, nodes.push(node) ) //存入结点
+
+                    if(last != void 0){//link
+                        if(last instanceof Array){//上个结点是分岔结束得到的数组
+                            last.forEach(lastEnd=>{
+                                addLink(lastEnd, cur) 
+                            })  
+                        }else{
+                            addLink(last, cur)
+                        }
+                    }
+                    last = cur 
+                })
+                return nodes.length - 1 //该条分岔的最后一个
+            }
+            //不可能出现连续数组的,也就是分岔完还分岔 
+            searchStart(data) 
+            
+        }else{
+            nodes = data
+        }
+        
+         
+        nodes.forEach(e=>{
+            newData.dataset_points.push(new THREE.Vector3().copy(e[dataset_points_name])) 
+            newData.points_datasets.push(e[points_datasets_name]) 
+        })
+         
+        return newData  
+    }
     
     createMeasureFromData(data){//add 
     
@@ -724,6 +783,11 @@ export class MeasuringTool extends THREE.EventDispatcher{
 };
 
 
+
+
+
+
+
 function updateAzimuth(viewer, measure){
     if(!measure.showAzimuth)return
 	const azimuth = measure.azimuth;

+ 8 - 7
src/custom/objects/tool/ctrlPolygon.js

@@ -22,7 +22,7 @@ export class ctrlPolygon extends THREE.Object3D {
         this.maxMarkers = Number.MAX_SAFE_INTEGER;
         
          
-        this.transformData(prop);
+        prop = this.transformData(prop);
         for(let i in prop){
             this[i] = prop[i]
         }
@@ -72,7 +72,9 @@ export class ctrlPolygon extends THREE.Object3D {
             }
         } 
         
-        
+        if(!prop.points && prop.dataset_points){
+            prop.points = prop.dataset_points.slice()
+        }
         
         if(prop.points){ 
             
@@ -91,7 +93,7 @@ export class ctrlPolygon extends THREE.Object3D {
                         this.transformByPointcloud() //根据dataset_points和this.datasetId生成points  
                     }  
                 }else{
-                    if(prop.dataset_points && prop.dataset_points.some(e=>e != void 0)){
+                    if(!prop.noDatasetId && prop.dataset_points && prop.dataset_points.some(e=>e != void 0)){
                         console.error('存在测量线的datasetId为空而dataset_points有值,请检查并删除:'+this.sid)//存在过的bug,原因未知,可能是后台处理dataset时替换的错误:http://192.168.0.21/index.php?m=bug&f=view&bugID=23601
                         console.log(this)
                     }
@@ -149,7 +151,7 @@ export class ctrlPolygon extends THREE.Object3D {
             o.marker.createTime = Date.now()
             
             let addHoverEvent = (e)=>{
-                if(o.marker._listeners?.startDragging || !this.editEnable)return //already has
+                if(o.marker._listeners?.mouseover || !this.editEnable)return //already has
                 
                 let mouseover = (e) => {  
                     this.setMarkerSelected(e.object, 'hover', 'single'); 
@@ -929,15 +931,14 @@ export class ctrlPolygon extends THREE.Object3D {
 		prop.showCoordinates = pick(prop.showCoordinates, false);
 		prop.showHeight = pick(prop.showHeight, false);
 		prop.showCircle = pick(prop.showCircle, false);
-		prop.showAzimuth = pick(prop.showAzimuth, false);
-		prop.showEdges = pick(prop.showEdges, true);
+		prop.showAzimuth = pick(prop.showAzimuth, false); 
 		prop.closed = pick(prop.closed, false);
 		prop.maxMarkers = pick(prop.maxMarkers, Infinity);
         prop.direction = prop.direction//add
 		prop.type = prop.type    
         prop.showGuideLine = pick(prop.showGuideLine, false);  
         prop.isRect = pick(prop.isRect, false);
-
+        return prop
     }
     setSelected(){}
     

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

@@ -1,5 +1,5 @@
 import * as THREE from "../../libs/three.js/build/three.module.js";
-
+import cameraLight from './utils/cameraLight.js'
 
 
 THREE.WebGLRenderer.prototype.paramThreeToGL = function(e) {
@@ -1031,4 +1031,10 @@ let oldSet = THREE.Color.prototype.set
 THREE.Color.prototype.set = function(){
     if(arguments.length >= 3)return this.setRGB.apply(this, arguments)
     return oldSet.apply(this, arguments)
-}
+}
+
+
+THREE.PerspectiveCamera.prototype.setMinFov = function(minFov=this.minFov){
+    this.minFov = minFov
+    this.fov = this.aspect < 1 ? cameraLight.getVFovByHFov(minFov, this.aspect) : minFov
+}

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

@@ -13,6 +13,9 @@ var cameraLight = {
         let rad = 2 * Math.atan(percent * Math.tan(fov * MathLight.RADIANS_PER_DEGREE / 2));
         if(getRad)return rad 
         else return rad * MathLight.DEGREES_PER_RADIAN;
+    },
+    getVFovByHFov(hFov, aspect){
+        return 2 * Math.atan(Math.tan(hFov * MathLight.RADIANS_PER_DEGREE / 2) / aspect)  * MathLight.DEGREES_PER_RADIAN 
     }
 };
 

+ 38 - 12
src/custom/utils/math.js

@@ -213,13 +213,8 @@ var math = {
 	
 	
 	
-	getFootPoint : function(oldPos, p1, p2, restricInline){ //找oldPos在线段p1, p2上的垂足
-		/* if(isWorld){//输出全局坐标 需要考虑meshGroup.position
-			p1 = p1.clone();
-			p2 = p2.clone();
-			p1.y += mainDesign.meshGroup.position.y;
-			p2.y += mainDesign.meshGroup.position.y;
-		} */
+	/* getFootPoint : function(oldPos, p1, p2, restricInline){ //找oldPos在线段p1, p2上的垂足
+		 
         if(p1.equals(p2))return p1.clone()
 		var op1 = oldPos.clone().sub(p1); 
 		var p1p2 = p1.clone().sub(p2)
@@ -233,11 +228,42 @@ var math = {
         }
         
 		return pos;
-	},
-
-	
-	
-	
+	}, */
+
+	// 更高效的版本(避免创建新对象,适合频繁调用)
+    getFootPoint(P, A, B, restricInline) {
+       
+        let result = new THREE['Vector'+ ((A.z != void 0) ? '3':'2')]  
+        const AB_x = B.x - A.x;
+        const AB_y = B.y - A.y;
+        const AB_z = B.z - A.z;
+        
+        const AP_x = P.x - A.x;
+        const AP_y = P.y - A.y;
+        const AP_z = P.z - A.z;
+        
+         
+        const dot_AP_AB = AP_x * AB_x + AP_y * AB_y + (A.z != void 0 ? AP_z * AB_z : 0);
+        const dot_AB_AB = AB_x * AB_x + AB_y * AB_y + (A.z != void 0 ? AB_z * AB_z : 0); 
+        
+        // 避免除零
+        if (dot_AB_AB === 0) {
+            return result.copy(A);
+        }
+        
+        let t = dot_AP_AB / dot_AB_AB 
+        if(restricInline){
+            t = THREE.Math.clamp(t, 0,1)
+        } 
+        
+        result.x = A.x + t * AB_x;
+        result.y = A.y + t * AB_y;
+        A.z != void 0 && (result.z = A.z + t * AB_z);
+        
+        return result;
+    },
+        
+ 
 	
 	
 	/**

+ 43 - 13
src/custom/viewer/ViewerNew.js

@@ -128,7 +128,7 @@ THREE.Cache.enabled = true //这样不会重复网络请求相同的图(如热
 export class Viewer extends ViewerBase{
 	
 	constructor(domElement, mapArea_, args = {}){
-		super(domElement, $.extend(args,{name:'mainViewer', antialias:true, preserveDrawingBuffer:true}));
+		super(domElement, $.extend(args,{name:'mainViewer', antialias: !browser.urlHasValue('noAA'), preserveDrawingBuffer:true}));
         //注:viewer因为要分屏,尤其是四屏,preserveDrawingBuffer需要为true, 否则无法局部clear 
         
         window.viewer = this
@@ -1969,14 +1969,18 @@ export class Viewer extends ViewerBase{
 		return this.edlOpacity;
 	};
 
-	setFOV (value) {
-		if (this.fov !== value) {
-            let oldFov = this.fov
-			this.fov = value;
+	setFOV (value) { 
+        let oldFov = this.scene.cameraP.fov
+        this.fov = value;
+        if(Potree.settings.keepMinFov){
+            this.scene.cameraP.setMinFov(this.fov)
+        }else{
             this.scene.cameraP.fov = this.fov;  //add
+        } 
+        if(oldFov != this.scene.cameraP.fov){
             this.scene.cameraP.updateProjectionMatrix() //add
-			this.dispatchEvent({'type': 'fov_changed', 'viewer': this,  oldFov, fov:this.fov});
-		}
+            this.dispatchEvent({'type': 'fov_changed', 'viewer': this,  oldFov, fov:this.scene.cameraP.fov});
+        }
 	};
 
 	getFOV () {
@@ -3754,6 +3758,10 @@ export class Viewer extends ViewerBase{
     https://blog.csdn.net/weixin_30378311/article/details/94846947 */
      
 	async render(params={}){//add params 
+    
+        //return viewer.dispatchEvent({type: "render.end" , viewer:this, viewport:this.mainViewport });
+        if(this.pauseRender)return
+    
         viewer.addTimeMark('render','start')
         const vrActive = this.renderer.xr.isPresenting;
         let {SiteModel,PanoEditor} = viewer.modules
@@ -5095,18 +5103,41 @@ export class Viewer extends ViewerBase{
 	}
 
 	loop(timestamp){
+        /* this.dispatchEvent('loopStart')
+        let deltaTime_ = this.clock.getDelta() 
+        TWEEN.update(timestamp);
+        transitions.update(deltaTime_);//写在开头,因为这时候最为固定,计时准确
+        
+        this.updateScreenSize() //判断是否改变canvas大小
+        this.controls.update(deltaTime_);
+        //更新camera
+        this.viewports.forEach(viewport=>{
+            if(!viewport.active)return
+            viewport.view.applyToCamera(viewport.camera)  
+              
+        }) 
+        this.lastFrameChanged = this.cameraChanged()//判断camera画面是否改变
+        
+        
+		//this.update(deltaTime, timestamp);
+        this.dispatchEvent({type: "render.end",  viewer: this, viewport:this.mainViewport  }); 
+    return */
+        //--------------------------------------
+        
+        
+        
         //let startTime = performance.now()
         //console.log('间隔:' /*, parseInt((startTime - this.lastEndTime)*100 )/100 */)
-        if(this.paused)return 
+        if(this.paused)return this.dispatchEvent({type:'loopStart1', delta:this.clock.getDelta()}) 
         if(performance.getEntriesByName("loopWaitNext-start").length)viewer.addTimeMark('loopWaitNext','end') 
          
          
 		if(this.stats){
 			this.stats.begin();
 		}
-       
+        let deltaTime = this.clock.getDelta()
         performance.mark('loop-start') ;// 无论有没有reportTimings都要获取,因为getBestCound需要
-        this.dispatchEvent('loopStart')
+        this.dispatchEvent({type:'loopStart', delta:deltaTime})
         
         
         this.interacted = false
@@ -5115,8 +5146,7 @@ export class Viewer extends ViewerBase{
         
        
 
-        let deltaTime = this.clock.getDelta()
-        
+       
         
         
 		this.update(deltaTime, timestamp);
@@ -5125,7 +5155,7 @@ export class Viewer extends ViewerBase{
         
         viewer.addTimeMark('loop2','start')
         this.render(); 
-        viewer.addTimeMark('loop2','end') 
+        viewer.addTimeMark('loop2','end')  
         
         
         

+ 4 - 3
src/custom/viewer/viewerBase.js

@@ -36,7 +36,7 @@ export class ViewerBase extends THREE.EventDispatcher{
 
         let width = this.renderArea.clientWidth;
         let height = this.renderArea.clientHeight;
-
+console.log('antialias',args.antialias)
         let contextAttributes = {
             alpha: true,//支持透明
             depth: true,
@@ -194,8 +194,9 @@ export class ViewerBase extends THREE.EventDispatcher{
                     
                     
                 }else{   
-                
-                
+                    if(view.camera.minFov){
+                        view.camera.setMinFov()  //update fov
+                    }  
                 }
                 
                 view.camera.updateProjectionMatrix();

+ 10 - 12
src/navigation/FirstPersonControlsNew.js

@@ -84,9 +84,10 @@ export class FirstPersonControls extends THREE.EventDispatcher {
              
              
             if(e.isTouch){
-                if(e.touches.length == 1){
+                let touches = e.touches 
+                if(touches.length == 1){
                     mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan' 
-                }else if(e.touches.length == 2){
+                }else if(touches.length == 2){
                     mode = Potree.settings.displayMode == 'showPanos' ? 'scale' :  'pan-scale'
                 }else{
                     mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'pan' : 'scale' 
@@ -95,18 +96,15 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                 //mode = e.buttons === Buttons.LEFT && (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan'
                 mode = e.buttons === Buttons.LEFT && camera.type != 'OrthographicCamera' ? 'rotate' : 'pan'
             }
-            
-            
-            
-            //console.log('mode  ', mode )
+      
+            //mode != 'rotate' && console.log('mode  ', mode )
             let moveSpeed = this.currentViewport.getMoveSpeed();
             if (e.drag.startHandled === undefined) {///???????
 				e.drag.startHandled = true;
 
 				this.dispatchEvent({type: 'start'});
 			}
-            
-            
+             
             if (mode.includes('rotate')) {//旋转 
 				
                 //来自panoramaControl updateRotation
@@ -835,12 +833,13 @@ export class FirstPersonControls extends THREE.EventDispatcher {
 
 		{ // apply rotation
 			let yaw = view.yaw;
-			let pitch = view.pitch;
-             
+			let pitch = view.pitch; 
             
 			yaw += this.yawDelta /* * delta; */
 			pitch += this.pitchDelta/*  * delta; */
 
+           //this.yawDelta > 0.001 && console.log('yaw', this.yawDelta )
+
 			view.yaw = yaw;
 			view.pitch = pitch;
             if(this.yawDelta || this.pitchDelta){
@@ -887,8 +886,7 @@ export class FirstPersonControls extends THREE.EventDispatcher {
             
             
 		}
- 
-
+  
         if(this.useAttenuation){ //只有滚轮缩放时开启
 			let attenuation = Math.max(0, 1 - this.fadeFactor * delta);
           

+ 14 - 9
src/navigation/InputHandlerNew.js

@@ -155,17 +155,22 @@ export class InputHandler extends THREE.EventDispatcher {
     updateTouchesInfo(e){
         var viewport, pointer, camera  
         let oldTouches = this.touches
-        let changedTouches = Array.from(e.changedTouches)
-        let touches = Array.from(e.touches)
+        let changedTouches = Array.from(e.changedTouches).filter(e=>e.target == this.domElement  )
+        let touches = Array.from(e.touches).filter(e=>e.target == this.domElement  )
 
         this.touches = touches.map(touch=>{
             let touch_ = oldTouches.find(a=>a.touch.identifier == touch.identifier)
             let pointer = touch_ && touch_.pointer  //复制原先的值
+            //let isAtDomElement = touch.target == this.domElement 
             return { 
-                touch,   pointer, 
+                touch,   pointer,  //isAtDomElement
             }
         }) 
-        if(e.touches.length > 0){ 
+        
+        
+        
+        
+        if(touches.length > 0){ 
             
             let newTouches = touches.filter(e=>!
                 oldTouches.some(a=>a.touch.identifier == e.identifier) && !changedTouches.some(a=>a.identifier == e.identifier)  
@@ -186,17 +191,17 @@ export class InputHandler extends THREE.EventDispatcher {
             
             
             //使用当前touches的平均
-            if(e.touches.length > 1){
-                let pageX = Common.average(e.touches, "pageX")
-                let pageY = Common.average(e.touches, "pageY")
+            if(touches.length > 1){
+                let pageX = Common.average(touches, "pageX")
+                let pageY = Common.average(touches, "pageY")
                 let a = this.getPointerInViewport(pageX, pageY, viewport, new THREE.Vector2) 
                 this.pointer.copy(a.pointer)
-                //console.log('updateTouchesInfo', this.pointer.clone())
+                
                 
             }else{
                 this.pointer = this.touches[0].pointer.clone() //更新,使用当前touches中的第一个 
             }
-                
+            //console.log('touchesInfo', this.pointer.x.toPrecision(2), this.pointer.y.toPrecision(2) , this.touches.length)    
             
             /* if(this.touches.find(e=>!e.pointer)){
                 console.error('  touches has no pointer', oldTouches.map(e=>e.touch.identifier),

+ 2 - 2
src/navigation/OrbitControlsNew.js

@@ -417,8 +417,8 @@ export class OrbitControls extends THREE.EventDispatcher{
             }else if(moveDown){
                 pz = -1 * moveSpeed 
             }
-            
-            (px!=0 || py!=0 || pz!=0) && view.translate(px, py, pz, true); 
+            let forceHorizon = !Potree.settings.orbitCtlMoveFree  ;
+            (px!=0 || py!=0 || pz!=0) && view.translate(px, py, pz, forceHorizon); 
              
         }