xzw 7 месяцев назад
Родитель
Сommit
ee5f05eeb5

Разница между файлами не показана из-за своего большого размера
+ 23 - 9
src/Potree.js


+ 1 - 1
src/custom/mergeStartTest.js

@@ -399,7 +399,7 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
     
     
     
-    
+    Potree.setLonlat(113.60,22.36)
      
     
     let modelType,  modelEditing, MergeEditor = viewer.modules.MergeEditor

+ 2 - 1
src/custom/settings.js

@@ -551,7 +551,8 @@ let settings = {//设置   可修改
     
     //fastTran: isTest
     pathSmooth : true,// window.location.href.includes('192.168.0.59')  //true //smooth曲线, 非折线
-    maxClipFadeTime: 0.6
+    maxClipFadeTime: 0.6,
+    showMap3d: browser.urlHasValue('map3d'),
 }
  
 

+ 4 - 4
src/custom/start.js

@@ -23,7 +23,7 @@ var transformPointcloud = (pointcloud, dataset)=>{
     
     //dataset.orientation = 0
     let Alignment = viewer.modules.Alignment
-    Alignment.rotate(pointcloud, null, dataset.quaternion||dataset.orientation)   
+    Alignment.rotate(pointcloud, null, dataset.quaternion?.length == 4 ? dataset.quaternion : dataset.orientation)   
     Alignment.translate(pointcloud, new THREE.Vector3(location[0], location[1],  dataset.location[2]-baseZ)) //要使初始数据集的z为0,所以要减去初始数据集的z
     
     pointcloud.updateMatrixWorld()
@@ -285,10 +285,10 @@ export function start(dom, mapDom, number ){ //t-Zvd3w0m
         if(!Potree.settings.originDatasetId)Potree.settings.originDatasetId = data[0].id
         var originDataset = data.find(e=>e.id == Potree.settings.originDatasetId)  
         baseZ = originDataset.location[2]
-        /* originDataset.location[0] = 113.60608878174709
-        originDataset.location[1] = 22.381189423935155
+        /*originDataset.location[0] = 0
+        originDataset.location[1] = 0
           
-        let ano = data.find(e=>e.name == 'SG-t-Jw0xyhL6oSY')
+          let ano = data.find(e=>e.name == 'SG-t-Jw0xyhL6oSY')
         ano.location[0] = 113.6060509967498
         ano.location[1] = 22.381061273279244 */
         

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

@@ -664,7 +664,32 @@ var math = {
     },
     getCelsiusFromKelvin(c){  
         return c - 273.1  
+    },
+    
+    
+
+    fromCes(cartesian, getLonlat){
+        var cartographic = Cesium.Cartographic.fromCartesian(cartesian); 
+        var lng = Cesium.Math.toDegrees(cartographic.longitude);
+        var lat = Cesium.Math.toDegrees(cartographic.latitude);
+        var height = cartographic.height;
+        let loc = new THREE.Vector3(lng, lat, height)
+        if(getLonlat)return loc
+        return viewer.transform.lonlatToLocal.forward(loc)   
+    },
+    toCes(pos){
+        let xy = [pos.x, pos.y];
+        let height = pos.z;
+        let deg = viewer.transform.lonlatToLocal.inverse(xy)  //  toMap.forward(xy);
+        let cPos = Cesium.Cartesian3.fromDegrees(...deg, height);//console.log('toCes',cPos,height) //数字过大如e35会崩溃
+        
+        return cPos;
     }
+    
+        
+   
+    
+    
 };
 
 /* 

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

@@ -31,7 +31,7 @@ import {Renderer} from "../../PotreeRendererNew.js";
 import {EDLRenderer} from "../../viewer/EDLRendererNew.js";
 import {HQSplatRenderer} from "../../viewer/HQSplatRenderer.js";
 import {MapViewer} from "./map/MapViewer.js";     
-import {MapLayer} from "./map/Map3D.js"     
+import {MapLayer} from "./map/Map.js"     
       
 import {NavigationCube} from '../../viewer/NavigationCube.js'
    
@@ -567,13 +567,28 @@ export class Viewer extends ViewerBase{
                     
                     
                 }
-                /*  {//test
-                    this.map3d = new MapLayer(this,this.mainViewport)//new Map3D(this)
+                if(Potree.settings.showMap3d){//test
+                 
+                    this.map3d = new MapLayer(this,this.mainViewport,true) 
                     this.scene.scene.add(this.map3d.sceneGroup)
+                    this.map3d.disabled = true
                     this.map3d.addEventListener('loadDone',()=>{
                         this.dispatchEvent('content_changed')
                     })
-                } */
+                    this.map3d.addEventListener('tileLoaded',()=>{
+                        Potree.Common.intervalTool.isWaiting('mapUpdateTile', () => {  
+                             this.dispatchEvent('content_changed') //渲染 尤其vpn访问google网速慢需要
+                        }, 1000);  
+                    })
+                    
+                    this.map3d.sceneGroup.position.z = -20
+                    this.addEventListener('setLonlat',(e)=>{
+                        this.map3d.disabled = false
+                        Potree.settings.cameraFar = 80000000 
+                     
+                    },{once:true}) 
+                     
+                }   
                  
                 
                 this.inputHandler = new InputHandler(this, this.scene.scene);
@@ -3626,6 +3641,12 @@ export class Viewer extends ViewerBase{
               
         }
         
+        if(this.map3d){
+            Potree.Utils.setCameraLayers(viewport.camera,  ['map'] )  
+            viewer.renderer.render(this.scene.scene, viewport.camera);  
+            
+        }
+        
         //全景图的部分和点云有点相关就不移动到这了。但是如果是showPanos模式,就不要渲染背景了。
         
     }
@@ -5151,9 +5172,11 @@ export class Viewer extends ViewerBase{
             window.pauseAni || this.objs.children.forEach(model=>{
                 //model.traverse(object=>object.isSkinnedMesh && object.computeBoundingSphere())
                 
-                if(model.mixer && model.mixer._nActiveActions){ 
+                if(model.mixer && (model.clipChanged || model.actions.some(a=>a._mixer._isActiveAction( a ) && !a.paused ))){ //播放中或者动作状态改变
                     hasAnimation = true
+                    model.clipChanged = false
                     model.mixer.update(deltaTime)
+                    //console.log('mixer update', model.name)
                 }
             }) //以后有空的话用frust判断是否在画面内,不在的话即使有动画也不要 update 和 render, 如果paused的话是不是也可以不update
             hasAnimation && (this.dispatchEvent('content_changed'))

+ 301 - 127
src/custom/viewer/map/Map.js

@@ -4,7 +4,20 @@ import browser from '../../utils/browser.js'
 
 import BasicMaterial from '../../materials/BasicMaterial.js'  
     
-
+import {TextSprite} from "../../objects/TextSprite.js"; 
+ 
+window.showTileName = false
+//将原先的map写成3d的
+const radius = 6378137//.050041738 //地图mapSizeM / 2 / Math.PI 
+const makeSphere = false 
+const earthCenter = new THREE.Vector3(0,0,-radius)
+let camDisToEarth = 0 //离地面的最近距离
+function getPosOnEarth(vertice, transform){
+    vertice = new THREE.Vector2().fromArray(transform.forward(vertice)) 
+    let disToZoroAxis = vertice.length() //到(0,0,1)轴的距离
+    let z = Math.sqrt(radius * radius - disToZoroAxis * disToZoroAxis)//在(0,0,1)轴的垂足距离球心 
+    return new THREE.Vector3(vertice.x, vertice.y, z - radius)//(0,0)处地表z为0,其余都在0之下
+}
 
 let texLoader = new THREE.TextureLoader() 
     texLoader.crossOrigin = "anonymous" 
@@ -51,8 +64,9 @@ const getSid = (function(){
  
 
 export class MapLayer extends THREE.EventDispatcher{ // 包括了 MapLayerBase SceneLayer
-    constructor(viewer_, viewport){
+    constructor(viewer_, viewport, is3d){
         super()
+        this.is3d = is3d
         this.sceneGroup = new THREE.Object3D;
         this.sceneGroup.name = "MapLayer" 
         this.waitQueue = [] //等待加载的
@@ -184,6 +198,7 @@ export class MapLayer extends THREE.EventDispatcher{ // 包括了 MapLayerBase S
         this.frustum.planes[5].setComponents(0, 0, 0, 0),
         i = !0 
         
+        camDisToEarth = makeSphere ? (e.position.distanceTo(earthCenter) - radius) : (e.position.z - this.sceneGroup.position.z);
         //console.log('-------------update-----------')
         for (r = 0; r < this.maps.length; r++){
             var map = this.maps[r] 
@@ -245,8 +260,29 @@ export class TiledMapBase extends THREE.EventDispatcher{
         this.loadFailCount = 0
         this.loadingInProgress = 0
         
+        //add:
+        this.cache = [] //缓存。要删除的tile不立刻dispose,以便迅速再显示。每次都从第一个删除。
+        this.maxTotalCount = 1000
     }
-     
+    
+    cacheAutoClear(){//清除超出数量的缓存 add
+        let len = this.cache.length,  cacheCopy = this.cache.slice()
+        let overCount = this.objectGroup.children.length + len - this.maxTotalCount
+        if(overCount > 0){
+            let i = 0, delCount = Math.min(len, overCount) 
+            let dels = this.cache.splice(0,delCount)
+            dels.forEach(tile=>{ 
+                tile._mesh.material.dispose()
+                tile._mesh.geometry.dispose()
+                tile._mesh.material.map?.dispose()
+                tile._mesh = null
+                tile.textureLoaded = false
+            }) 
+             
+        }     
+    }
+    
+    
     get zoomLevel(){
         return this._zoomLevel
     }
@@ -269,13 +305,13 @@ export class TiledMapBase extends THREE.EventDispatcher{
     
     updateProjection(){ 
         if(!this.transformMapToLocal){
-            this.transformMapToLocal = proj4(this.projection, "LOCAL_MAP")   //由地图原本的坐标转为本地坐标
+            this.transformMapToLocal = proj4(this.projection, "LOCAL"/* _MAP" */)   //由地图原本的坐标转为本地坐标
         }  
     } 
     
     clearProjection(){
         this.transformMapToLocal = void 0 
-        this.projection !== 'LOCAL_MAP' && this.baseTile.remove()
+        this.projection !== 'LOCAL'/* _MAP' */ && this.baseTile.remove()
     }
     
     setEnable(enable){//add
@@ -298,6 +334,7 @@ export class TiledMapBase extends THREE.EventDispatcher{
     
    
     update(frustum, sceneGroup){
+         
         this.computeCount = 0 
         var unavailable = (this.disabled || !this.objectGroup.visible)//地图即使不显示也要获得zoomlevel
         if(this.name != 'map' && unavailable)return 
@@ -320,102 +357,161 @@ export class TiledMapBase extends THREE.EventDispatcher{
         o.project(viewport.camera);
         var rx = viewport.resolution.x 
           , ry = viewport.resolution.y 
-        if (rx <= 0 || ry <= 0 || isNaN(i.x) || isNaN(o.x))  return !1;
+        if (rx <= 0 || ry <= 0 || isNaN(i.x) || isNaN(i.y) || isNaN(o.z))  return !1;
         i.sub(o),
         i.x *= rx / 2,
         i.y *= ry / 2;
         
         
          
-        let scale  
-        if(this.name == 'map'){ 
+        let scale=1, level
+        if(this.name == 'map' && !this.mapLayer.is3d){ 
             //add 高纬度的因倾斜而造成tile较小,所以放大些,否则会造成显示的tile过多而卡
             let lonlat = viewer.transform.lonlatToLocal.inverse(viewport.camera.position.clone()) 
             let cos = Math.cos(THREE.Math.degToRad(lonlat.y)); //越小就在纬度上越高,tile表现越小
-            //为什么lonlat.y会超出90?
-            /* if(lonlat.y>90){
-                console.log('lonlat.y>90',lonlat.y)
-            }  */
-            
+            //为什么lonlat.y会超出90? 
             cos = THREE.Math.clamp(cos, 0,1)
             let lonShift =  Math.abs(viewer.mapViewer.camera.position.x / this.mapSizeM * 16  )  //越大就在经度离中心越远,tile表现越大  。  
             lonShift = THREE.Math.clamp(lonShift, 0, Math.PI)
             lonShift = (1 - Math.sin( 1/2 * lonShift +  Math.PI/2 )) * Math.PI // 0-Math.PI   sin增速向上
             
             scale = 0.5 * cos * (1+lonShift)  +  0.5 * Math.pow(cos, lonShift)   
+        }
+     
+     
+        if(this.mapLayer.is3d){
+            level = this.maxDepth
         }else{
-            scale = 1
+            var c = this.tileSizePx / i.length() / scale      //多除以一个scale缩放因子,scale越大level越小
+            level = Math.ceil( -math.getBaseLog(2,c) - this.bias);
+            
+            if(this.style == 'dark-standard'){ //该模式贴图比较小放大点
+                level -= 1
+            } 
+            level = Math.max(level, 0) 
+            level = Math.min(level, void 0 === this.maxDepth ? 1 / 0 : this.maxDepth)  
+            this.zoomLevel = level//add 
+            /* if(isNaN(this.zoomLevel )){ 
+                console.log(level, cos , scale , lonlat )
+            } */ 
         }
         
-        var c = this.tileSizePx / i.length() / scale      //多除以一个scale缩放因子,scale越大level越小
-          , level = Math.ceil( -math.getBaseLog(2,c) - this.bias);
-        
-        if(this.style == 'dark-standard'){ //该模式贴图比较小放大点
-            level -= 1
-        } 
-        level = Math.max(level, 0) 
-        level = Math.min(level, void 0 === this.maxDepth ? 1 / 0 : this.maxDepth)  
-        
-        
-        this.zoomLevel = level//add
-        
-        
-        /* if(isNaN(this.zoomLevel )){ 
-            console.log(level, cos , scale , lonlat )
-        } */
         
         if(!unavailable){
             this.addToSceneGroup(sceneGroup) 
-            return this.baseTile.update(this, frustum, level, this.mapSizeM, 0, 0, "")
+            /* return  */this.baseTile.update(this, frustum, level, this.mapSizeM, 0, 0, "", viewport)
+            this.cacheAutoClear() 
         }
+        
+        
     }
      
      
      
      
-    isTileVisible(tileCenter, tileSize, frustum){ 
+    isTileVisible(tileCenter, tileSize, frustum, viewport, name){ 
         if (tileSize > HALF_WORLD_SIZE) return !0;  //root must visible
         var halfSize = .5 * tileSize; //在地图上的size和local的差不多是吗
-         
-        //简单版:
-        this.transformMapToLocal.forward(tileCenter) //e转化为local
+        let vertices = []
+         //简单版:          
+        if(makeSphere){
+            tileCenter = getPosOnEarth(tileCenter.toArray(), this.transformMapToLocal )
+        }else{
+            this.transformMapToLocal.forward(tileCenter) //e转化为local 
+            //tileCenter.sub(this.objectGroup.parent.position)                  
+        }                                                     
         this.isTileVisibleBox.makeEmpty() 
         this.isTileVisibleVec.set(tileCenter.x - halfSize, tileCenter.y - halfSize, tileCenter.z).applyMatrix4(this.objectGroup.matrixWorld)
+        vertices.push(this.isTileVisibleVec.clone())
         this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec)
+        
         this.isTileVisibleVec.set(tileCenter.x - halfSize, tileCenter.y + halfSize, tileCenter.z).applyMatrix4(this.objectGroup.matrixWorld)
+        vertices.push(this.isTileVisibleVec.clone())
         this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec)
+        
         this.isTileVisibleVec.set(tileCenter.x + halfSize, tileCenter.y - halfSize, tileCenter.z).applyMatrix4(this.objectGroup.matrixWorld)
+        vertices.push(this.isTileVisibleVec.clone())
         this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec)
+        
         this.isTileVisibleVec.set(tileCenter.x + halfSize, tileCenter.y + halfSize, tileCenter.z).applyMatrix4(this.objectGroup.matrixWorld)
+        vertices.push(this.isTileVisibleVec.clone())
         this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec) 
-          
-      
+         
+        let visi = frustum.intersectsBox(this.isTileVisibleBox)  
+                                                                  
+       
         
-        //仿造createMesh写的准确版,但会因为大的tile非矩形,而视口是矩形,若视口刚好在tile的曲线边缘外却识别为可见,就会创建冗余tile。 但上面那个简单版在zoomlevel低的时候地球边缘容易有识别不到的tile,造成黑色三角形。
+        if(viewport && visi){
+            let canTraverse, vecs = []
+            let dis = tileCenter.distanceTo(viewport.camera.position) 
+         
+            //if(window.not111){
+            
+                let centerToCam = tileCenter.clone().applyMatrix4(viewport.camera.matrixWorldInverse)//相对位置
+                centerToCam.normalize() //dir 
+                 
+                let n = 1.1, v1 = 3, v2 = 7, v3 = 14
+                let a = dis / camDisToEarth
+                 
+                let r1 = math.linearClamp(a,[1,v1,v2,v3], [1, n, 1, 0.8]) //最近距离v1倍率处稍微提高
+                  
+                let r2 = math.linearClamp(Math.abs(centerToCam.x),[0, 0.7, 0.8], [1, 1.3, 1])  //相机两旁的提高
+                let r = r1 * r2 //使画面最近点附近的level提高些
+                 
+                r *= math.linearClamp(viewport.view.direction.z, [-1, -0.8 ], [a/r, 1]) //相机几乎垂直地面时,使全部level相同,类似2d
+                
+                canTraverse = tileSize / dis * r  > (window.number2 || 0.6)
+              
+           /*  }else{
+                 canTraverse = tileSize / dis   > (window.number2 || 0.6)
+             
+            }
+              */
+             
+             
+             
+             
+             
+            /* let pos2ds = vertices.map(e=> e.clone().project( viewport.camera)) //不管是否在背面了,太麻烦
+            //对角线长度
+            vecs.push(new THREE.Vector2().subVectors(pos2ds[0],pos2ds[2]))
+            vecs.push(new THREE.Vector2().subVectors(pos2ds[1],pos2ds[3])) 
+            
+            let lens = vecs.map(vec=>vec.multiply(viewport.resolution).length())
+            let px = Math.max(...lens)
+            canTraverse = px > this.tileSizePx * 4//1.414 */
+            
+            
+            
+            visi = {canTraverse} 
+            
+        }
+        
+        /* //仿造createMesh写的准确版,但会因为大的tile非矩形,而视口是矩形,若视口刚好在tile的曲线边缘外却识别为可见,就会创建冗余tile。 但上面那个简单版在zoomlevel低的时候地球边缘容易有识别不到的tile,造成黑色三角形。
         //容易出现奇怪的mesh
-         /* this.isTileVisibleBox.makeEmpty()
-        this.isTileVisibleVec.set(e.x - r, e.y - r, e.z) 
+        this.isTileVisibleBox.makeEmpty()
+        this.isTileVisibleVec.set(tileCenter.x - halfSize, tileCenter.y - halfSize, tileCenter.z) 
         this.transformMapToLocal.forward(this.isTileVisibleVec)
         this.isTileVisibleVec.applyMatrix4(this.objectGroup.matrixWorld)
         this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec)
         
-        this.isTileVisibleVec.set(e.x - r, e.y + r, e.z) 
+        this.isTileVisibleVec.set(tileCenter.x - halfSize, tileCenter.y + halfSize, tileCenter.z) 
         this.transformMapToLocal.forward(this.isTileVisibleVec)
         this.isTileVisibleVec.applyMatrix4(this.objectGroup.matrixWorld)
         this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec)
         
-        this.isTileVisibleVec.set(e.x + r, e.y - r, e.z) 
+        this.isTileVisibleVec.set(tileCenter.x + halfSize, tileCenter.y - halfSize, tileCenter.z) 
         this.transformMapToLocal.forward(this.isTileVisibleVec)
         this.isTileVisibleVec.applyMatrix4(this.objectGroup.matrixWorld)
         this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec)
         
-        this.isTileVisibleVec.set(e.x + r, e.y + r, e.z) 
+        this.isTileVisibleVec.set(tileCenter.x + halfSize, tileCenter.y + halfSize, tileCenter.z) 
         this.transformMapToLocal.forward(this.isTileVisibleVec)
         this.isTileVisibleVec.applyMatrix4(this.objectGroup.matrixWorld)
-        this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec)  */
-            
+        this.isTileVisibleBox.expandByPoint(this.isTileVisibleVec)  
+             */
        
-        return frustum.intersectsBox(this.isTileVisibleBox)  
+        return visi
          
         
         
@@ -458,7 +554,8 @@ const loadDone = (tile, success)=>{
             tile.map.mapLayer.dispatchEvent('loadDone') 
         }
     }
-    tile.mesh && (tile.mesh.material.needsUpdate = true)
+    let mesh = tile.mesh ||  tile._mesh 
+    mesh && (mesh.material.needsUpdate = true)
     
 }
  
@@ -485,15 +582,19 @@ function addLoadTile(tile){
         
         
         let tex = tile.mesh.material.map = texLoader.load(tile.texURL, (tex)=>{      //如果一直加载不了会影响其他的加载,如google地图没有vpn会使全景图一直加载不了
-            if(tile.mesh){//如果还要显示的话
+            let mesh = tile.mesh || tile._mesh
+            if(mesh){//如果还存在的话
                 tile.textureLoaded = true
-                tile.mesh.material.opacity = 1  
-                tile.map.mapLayer.viewer.mapChanged = true
-                tile.map.mapLayer.needUpdate = true //表示还要继续update(以removeChildren)
-                
-                if(tile.map instanceof TiledMapOpenStreetMap){
-                    tile.map.maxLoading = browser.isMobile() ? 5 : 10; 
-                } 
+                mesh.material.opacity = mesh.clockwise ? 0 : 1
+                if(tile.mesh){//显示的话
+                    tile.map.mapLayer.viewer.mapChanged = true
+                    tile.map.mapLayer.needUpdate = true //表示还要继续update(以removeChildren)
+                    
+                    if(tile.map instanceof TiledMapOpenStreetMap){
+                        tile.map.maxLoading = browser.isMobile() ? 5 : 10;    
+                    } 
+                    tile.map.mapLayer.dispatchEvent('tileLoaded')
+                }
             }else{
                 //tile.texURL && tile.texURL.includes('testdata') && console.log('loadDone and dispose',   tile.texURL.split('map_tiles/')[1] )
                 tex.dispose()   
@@ -513,11 +614,16 @@ function addLoadTile(tile){
                 tile.map.maxLoading = 2;
             }
             
-        }))  
-        tex.anisotropy = 0 
-        tex.generateMipmaps = !1 
-        tex.minFilter = THREE.LinearFilter 
-        tex.magFilter = THREE.LinearFilter 
+        })) 
+        if(tile.map.mapLayer.is3d){
+            tex.anisotropy = 2
+        }else{
+            tex.anisotropy = 0 
+            tex.generateMipmaps = !1 
+            tex.minFilter = THREE.LinearFilter 
+            tex.magFilter = THREE.LinearFilter 
+        }
+        
           
     }else{
         tile.map.mapLayer.waitQueue.includes(tile) || tile.map.mapLayer.waitQueue.push(tile) 
@@ -546,8 +652,13 @@ export class MapTile{
         this.children = []
         this.id = getSid();
     }
-    update(entity, frustum, level, tileSize, centerX, centerY, treeStr){
-        return !!this.doesNotContainTilesToBeDisplayed(entity) || (0 === level ? this.updateTileLeaf(entity, tileSize, centerX, centerY ) : this.updateSubTiles(entity, frustum, level, tileSize, centerX, centerY, treeStr))
+    update(entity, frustum, level, tileSize, centerX, centerY, treeStr, viewport, canTraverse=true){
+        if(!this.doesNotContainTilesToBeDisplayed(entity) ){
+            let canTraverse_ = this.map.mapLayer.is3d ? canTraverse :  level > 0
+            return (canTraverse_ ? this.updateSubTiles(entity, frustum, level, tileSize, centerX, centerY, treeStr, viewport) : this.updateTileLeaf(entity, tileSize, centerX, centerY )  )
+            
+        }                                                                     
+           
     } 
     
     doesNotContainTilesToBeDisplayed(entity){
@@ -575,7 +686,7 @@ export class MapTile{
         return this.textureLoaded
     }
     
-    updateSubTiles(entity, frustum, level, tileSize, centerX, centerY, treeStr){
+    updateSubTiles(entity, frustum, level, tileSize, centerX, centerY, treeStr, viewport){
         //if(entity.name.includes('floorplan'))console.log('updateSubTiles',this.name) //名字越长代表level越高
         
         let shiftX = [-.25 * tileSize, .25 * tileSize, -.25 * tileSize, .25 * tileSize], 
@@ -592,13 +703,17 @@ export class MapTile{
                 tempVector.set(childCenterX, childCenterY, 0);
                 this.map.computeCount ++
                 //console.log(this.map.computeCount, this.name, 'level:',level)
-                
-                if (entity.isTileVisible(tempVector, .5 * tileSize, frustum)){ 
+                let checkLevel = entity.mapLayer.is3d && level > 1  
+                if( entity.name == 'map' && checkLevel && entity.minDepth) checkLevel = level < entity.maxDepth - entity.minDepth //禁止地球显示层级过低否则无图且变形
+                let visi = entity.isTileVisible(tempVector, .5 * tileSize, frustum, checkLevel && viewport, this.name+p)
+                if (visi){                  
+                    //entity.name == 'map' && console.log('visi', childTreeStr, childCenterX,childCenterY, tileSize)
                     this.children[p] || (this.children[p] = new MapTile(this.map, this.objectGroup,this.tileColor, this, this.name+p ))
                     //childrenLoaded = childrenLoaded && this.children[p].update(entity, frustum, level - 1, .5 * tileSize, childCenterX, childCenterY, childTreeStr)   //这句会使若有一个tile还在加载,就阻断了。原版是这么写的。但是为了加快加载速度,改成下面两行。感觉直接全部updateTile也没太卡,不知道很大的场景会不会卡,单帧updateTile次数超过100次的话(应该不会吧,地图大小会限制住个数) -- 2023.12
-                    let childLoaded = this.children[p].update(entity, frustum, level - 1, .5 * tileSize, childCenterX, childCenterY, childTreeStr)  
+                    let childLoaded = this.children[p].update(entity, frustum,  level - 1,  .5 * tileSize, childCenterX, childCenterY, childTreeStr, viewport, level > 1 && visi.canTraverse)  
                     childrenLoaded = childrenLoaded && childLoaded
                 } else {
+                    //entity.name == 'map' && console.log('not visi',  childTreeStr, childCenterX,childCenterY, tileSize)
                     if (this.children[p]){
                         this.children[p].remove()
                         delete this.children[p]
@@ -620,71 +735,118 @@ export class MapTile{
     
      */ 
     createTileObject(entity, tileSize, centerXatMap, centerYatMap){
-        var s = this;
-        this.mesh = this.createMesh(entity.transformMapToLocal,tileSize, centerXatMap, centerYatMap),
-        this.textureLoaded = !1;
-        var c = entity.mapSizeM / tileSize
-          , z = math.getBaseLog(2,c) //以2为底c的对数
-          , x = centerXatMap / tileSize + .5 * (c - 1)
-          , y = -centerYatMap / tileSize + .5 * (c - 1)
-          , p = entity.getTileUrl(Math.round(x), Math.round(y), Math.round(z));
-        Potree.Utils.setObjectLayers(this.mesh, 'map' )
-        this.mesh.renderOrder = -(1e6 - z - 100 * (entity.zIndex || 0));
-        this.mesh.name = this.name //add
-        this.texURL = p
-        
-        /* let area = math.getArea(this.mesh.geometry.vertices.slice(0,3));
-        if(area >0){
-            this.mesh.visible = false
-            console.log('area>0',this.mesh.name)
-        } */
-        addLoadTile(this)
-        
+     
+        let tileIndex = this.map.cache.findIndex(e=>e == this)
+       
+        if(tileIndex == -1){  
+            mesh = this.createMesh(entity.transformMapToLocal,tileSize, centerXatMap, centerYatMap),
+            mesh.name = this.name 
+            if(showTileName){
+                this.textureLoaded = !0;   //add 
+            }else{
+                this.textureLoaded = !1;
+                var c = entity.mapSizeM / tileSize
+                  , z = math.getBaseLog(2,c) //以2为底c的对数
+                  , x = centerXatMap / tileSize + .5 * (c - 1)
+                  , y = -centerYatMap / tileSize + .5 * (c - 1)
+                  , p = entity.getTileUrl(Math.round(x), Math.round(y), Math.round(z));
+                Potree.Utils.setObjectLayers(mesh, 'map' )
+                mesh.renderOrder = -(1e6 - z - 100 * (entity.zIndex || 0));
+                
+                this.texURL = p
+                newBuilt = true
+                
+            }   
+            //this.map.cacheAutoClear() //增加一个就可能要减少一个  
+        }else{ 
+            
+            mesh = this.map.cache.splice(tileIndex,1)[0]//从缓存取出 
+        }
+           
+        this.mesh = mesh 
+        tileIndex > -1 && addLoadTile(this)
     }
     
-    createMesh(transform, tileSize, centerXatMap, centerYatMap){
-        var a = new THREE.Geometry;
-        return tempVector.set(centerXatMap - tileSize / 2, centerYatMap - tileSize / 2, 0),
-        a.vertices.push(new THREE.Vector3().copy(transform.forward(tempVector))),
+  /* getVertices(transform, tileSize, centerXatMap, centerYatMap){
+        this.vertices = []
+        tempVector.set(centerXatMap - tileSize / 2, centerYatMap - tileSize / 2, 0),
+        this.vertices.push(new THREE.Vector3().copy(transform.forward(tempVector))),
         tempVector.set(centerXatMap + tileSize / 2, centerYatMap - tileSize / 2, 0),
-        a.vertices.push(new THREE.Vector3().copy(transform.forward(tempVector))),
+        this.vertices.push(new THREE.Vector3().copy(transform.forward(tempVector))),
         tempVector.set(centerXatMap + tileSize / 2, centerYatMap + tileSize / 2, 0),
-        a.vertices.push(new THREE.Vector3().copy(transform.forward(tempVector))),
+        this.vertices.push(new THREE.Vector3().copy(transform.forward(tempVector))),
         tempVector.set(centerXatMap - tileSize / 2, centerYatMap + tileSize / 2, 0),
-        a.vertices.push(new THREE.Vector3().copy(transform.forward(tempVector))),
+        this.vertices.push(new THREE.Vector3().copy(transform.forward(tempVector))) 
+        
+    } */
+    
+    createMesh(transform, tileSize, centerXatMap, centerYatMap){
+        var a = new THREE.Geometry;
+        let vertices = [
+            [centerXatMap - tileSize / 2, centerYatMap - tileSize / 2],
+            [centerXatMap + tileSize / 2, centerYatMap - tileSize / 2],
+            [centerXatMap + tileSize / 2, centerYatMap + tileSize / 2],
+            [centerXatMap - tileSize / 2, centerYatMap + tileSize / 2]
+        ]                                                          
+        vertices.forEach(vertice=>{//计算在球面上的位置, xy已经有了,算z 
+            if(makeSphere){
+                a.vertices.push(getPosOnEarth(vertice, transform) )//(0,0)处地表z为0,其余都在0之下
+            }else{
+                a.vertices.push(new THREE.Vector3().fromArray([...transform.forward(vertice),0]))
+            }
+        })
+        
+        
+         
         a.faces.push(face1),
         a.faces.push(face2),
         a.faceVertexUvs[0].push(face1UV),
-        a.faceVertexUvs[0].push(face2UV),
-        new THREE.Mesh(a,this.createMaterial())
+        a.faceVertexUvs[0].push(face2UV) 
+        let label  
+        if(showTileName){
+            //let center = this.tilePos || new THREE.Vector3().fromArray(transform.forward([centerXatMap,centerYatMap,0])) 
+            label = new TextSprite({text: this.name, sizeInfo:{width2d:200}, fontsize:60, 
+                textColor: {r:30, g: 30, b: 30, a:1}, backgroundColor: {r:255, g: 255, b: 255, a:0.98},
+            })
+            /* label.position.copy(center)
+            mesh.add(label) */
+        }
+        
+        let mesh = new THREE.Mesh(a,this.createMaterial(label))
+        
+        if(this.map.mapLayer.is3d){
+            let clockwise = math.getArea(a.vertices) > 0;
+            mesh.clockwise = clockwise 
+            showTileName && (mesh.material.opacity = clockwise ? 0  : 1)//soon
+        }
+       
+            
+         
+        return mesh                                                                                       
     }
     
-    createMaterial(){
+    createMaterial(label){
+        let color 
+        
+        if(Potree.settings.isTest) {
+            var colorHue = Math.random()
+            color = new THREE.Color().setHSL(colorHue, 0.6, 0.92) 
+        }else{
+            color = this.tileColor ? this.tileColor : new THREE.Color(16777215) 
+        }
+         
+        
         var t = new THREE.MeshBasicMaterial({
             transparent: !0,
             depthWrite: !1,
-            depthTest: !0,
+            depthTest: !1, //!0
             opacity: 0,
             side: THREE.DoubleSide,
-           
+            color,
         }); 
         
-        
-        /* var t = new BasicMaterial({
-            transparent: !0,
-            depthWrite: !1,
-            depthTest: !0,
-            opacity: 0,
-            side: THREE.DoubleSide
-        })
-         t.defines.InverseColor = '' */
-        
-        if(Potree.settings.isTest) {
-            var colorHue = Math.random()
-            t.color = new THREE.Color().setHSL(colorHue, 0.6, 0.92) 
-        }else{
-            t.color = this.tileColor ? this.tileColor : new THREE.Color(16777215) 
-        }
+        label && (t.map = label.sprite.material.map) //add
+         
         
         return t
     }
@@ -701,20 +863,28 @@ export class MapTile{
     removeObject3D(){
         let hasMesh = !!this.mesh
         if (this.mesh){
+            
+            if(this.mesh.material.map){//add 已经有图或在加载图
+                this.mesh_ = this.mesh 
+                this.map.cache.push(this) //加入缓存
+            }else{
+                cancelLoad(this)
+            }
             this.objectGroup.remove(this.mesh)
-            if (this.textureLoaded){
+            
+            /* if (this.textureLoaded){
                 var t = this.mesh.material.map;
                 t && t.dispose() 
             }else{
                 cancelLoad(this)
-            } 
+            }   
             
             this.mesh.material.dispose() //o.disposeMeshMaterial(this.mesh),
-            this.mesh.geometry.dispose() 
+            this.mesh.geometry.dispose()  */
             this.mesh = void 0
         }
-        this.meshAdded = !1,
-        this.textureLoaded = !1
+        this.meshAdded = !1 
+        
         //this.texURL && this.texURL.includes('testdata') && console.log('removeObject3D', this.id, 'hasMesh',hasMesh, this.texURL.split('map_tiles/')[1] )
     }
     
@@ -737,9 +907,11 @@ export class MapTile{
 }
 
 
-
+//墨卡托全球矩形,无任何偏移: (地图资源是按照这个来获取的,不能偏移;而每个tile的具体位置则是这映射到local坐标后得到的,可以通过变换local的定义来改变transform映射。 )
 proj4.defs("EPSG:3857", "+title=WGS 84 / Pseudo-Mercator +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +no_defs")
-//这里地图世界的中心是不是lon:0,lat:0     
+   //注意在traverse四叉树会因为local的偏移而使边缘tile分裂为2块以上,尤其在子结点createMesh时就能看到那些图片拉伸的怪怪的tile,  我通过过滤掉clockwise来过滤掉这些错误mesh,因此缺少了一部分,全局看map左右不完整
+
+
 
 export class TiledMapOpenStreetMap extends TiledMapBase{
     constructor(mapLayer, tileColor){
@@ -751,9 +923,9 @@ export class TiledMapOpenStreetMap extends TiledMapBase{
         //this.baseUrl = "https://webrd01.is.autonavi.com/appmaptile?lang=zh_cn&size=1&scale=1&style=7&x=${x}&y=${y}&z=${z}" //最高只到18 level
         this.switchStyle()
         this.tileSizePx = 256
-        this.mapSizeM = 40075017   //总占据多少米(地球赤道周长)    和三维空间的不一样 - -, 空间上的是直径,地图上的是半个圆周
+        this.mapSizeM = Math.floor(6378137 * Math.PI * 2)//40075016, 不要超出地图projection范围  //  40075017   //总占据多少米(地球赤道周长)    和三维空间的不一样 - -, 空间上的是直径,地图上的是半个圆周
         this.bias = 0.5 
-         
+        this.minDepth = 1 //add  因0的无图或不全
         if(Potree.settings.mapCompany == 'google'){
             this.attribution = "© PopSmart,  © 谷歌地图"
             this.projection = "EPSG:900913"      //"EPSG:4326"//4550
@@ -786,8 +958,7 @@ export class TiledMapOpenStreetMap extends TiledMapBase{
                             + (glPos ? ("&gl=" + glPos) : '')
                             + "&x=${x}&y=${y}&z=${z}&s=mt1"
                           
-            this.maxDepth = 22
-            
+            this.maxDepth = 22 
             /* 1)lyrs= 表示的是图层类型,即瓦片类型,具体含义如下: 
             m:路线图 
             t:地形图 
@@ -810,6 +981,7 @@ export class TiledMapOpenStreetMap extends TiledMapBase{
         }else{
             //baseUrl = "https://webst01.is.autonavi.com/appmaptile?lang=zh_cn&style=6&yrs=m&x=${x}&y=${y}&z=${z}"    //卫星 maxDepth = 18   
             //搜索高德地图瓦片url 
+            
             if(Potree.settings.isJiangMen){
                 if(style == 'satellite'){//卫星
                     this.maxDepth = 18
@@ -901,7 +1073,7 @@ export class TiledMapFromEntity extends TiledMapBase{
     
     
     computeLocalCoordinates(){
-        if(proj4.defs("LOCAL_MAP")){
+        if(proj4.defs("LOCAL"/* _MAP" */)){
             
             let lonlat = this.tiledMapEntity.globalLocation
             /* if(window.AMapWith84){//需要转换
@@ -984,7 +1156,9 @@ export class TiledMapFromEntity extends TiledMapBase{
 
  /* 
  note:
- 
+ google地图看国内某个84经纬度和矫正后的高德的不一样,和未矫正后的高德接近.
+ map3d效果和高德地图差不多,原来高德也有三维的 https://www.amap.com/  
+ 高德限制了相机高度,使之不会到没有图的低level;且支持x轴无限滚动连接
  
  
  目前缩小了能看出形态是一个地球。相机在高空朝下观测,地球平放着。