xzw пре 1 година
родитељ
комит
706e8d1936

+ 2 - 2
examples/4dkk.html

@@ -49,13 +49,13 @@
         }
         if (number.indexOf("#") != -1) {
             number = number.substring(0, number.indexOf("#"));
-        }*/
+        }*/ 
         
         var number = browser.urlHasValue('m',true);
         console.log(number)
         Potree.start(document.getElementById("potree_render_area"),null, number);
         
-          
+           
 		/*
         数据集校准 平移后
         单个数据集:

Разлика између датотеке није приказан због своје велике величине
+ 15695 - 498
libs/Cesium/Cesium.js


+ 293 - 65
libs/three.js/3dtiles/three-loader-3dtiles.esm.js

@@ -7,7 +7,15 @@ import { KTX2Loader } from '../loaders/KTX2Loader.js';
 import MeshBasicMaterial  from '../../../src/custom/materials/BasicMaterial.js'  // xzw改  原先MeshBasicMaterial贴图发黑,可能和贴图有关
 
 let globalThis = window //add 有的app没有globalThis. 2023.1
+
+let rtcCenterGlobal = false//默认false,也就是scale.z要乘以-1
+
+
 /*! *****************************************************************************
+
+github: https://github.com/nytimes/three-loader-3dtiles
+
+
 Copyright (c) Microsoft Corporation.
 
 Permission to use, copy, modify, and/or distribute this software for any
@@ -22,13 +30,13 @@ OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
 PERFORMANCE OF THIS SOFTWARE.
 ***************************************************************************** */
 
-
+ 
 let visiVertexCount = 0
 let visiGeoCount = 0
 const maxVertexVisi = 5e6
 const maxTexVisi = 500
 
-
+const maxDepth = 100
 
 function getGpuMemoryUsage(win = window){//总的
     let c = 0
@@ -7777,7 +7785,7 @@ class OrientedBoundingBox {
 
   getBoundingSphere(result = new BoundingSphere()) {
     const halfAxes = this.halfAxes;
-    const u = halfAxes.getColumn(0, scratchVectorU);
+    const u = halfAxes.getColumn(0, scratchVectorU);//前三个
     const v = halfAxes.getColumn(1, scratchVectorV);
     const w = halfAxes.getColumn(2, scratchVectorW);
     const cornerVector = scratchVector3.copy(u).add(v).add(w);
@@ -7808,8 +7816,51 @@ class OrientedBoundingBox {
   distanceTo(point) {
     return Math.sqrt(this.distanceSquaredTo(point));
   }
+  /* distanceSquaredTo(point) {//相机到bound外壳的距离平方
+  
+    let center = this.center.clone()
+    center.z *= -1
+    
+    const offset = scratchOffset.from(point).subtract(center);
+    const halfAxes = this.halfAxes;
+    const u = halfAxes.getColumn(0, scratchVectorU);
+    const v = halfAxes.getColumn(1, scratchVectorV);
+    const w = halfAxes.getColumn(2, scratchVectorW);
+    
+    
+    u.z *= -1
+    v.z *= -1
+    w.z *= -1
+    
+    const uHalf = u.magnitude();
+    const vHalf = v.magnitude();
+    const wHalf = w.magnitude();
+    u.normalize();
+    v.normalize();
+    w.normalize();
+    let distanceSquared = 0.0;
+    let d;
+    d = Math.abs(offset.dot(u)) - uHalf;
 
-  distanceSquaredTo(point) {
+    if (d > 0) {
+      distanceSquared += d * d;
+    }
+
+    d = Math.abs(offset.dot(v)) - vHalf;
+
+    if (d > 0) {
+      distanceSquared += d * d;
+    }
+
+    d = Math.abs(offset.dot(w)) - wHalf;
+
+    if (d > 0) {
+      distanceSquared += d * d;
+    }
+
+    return distanceSquared;
+  } */
+  distanceSquaredTo(point) {//相机到bound外壳的距离平方
     const offset = scratchOffset.from(point).subtract(this.center);
     const halfAxes = this.halfAxes;
     const u = halfAxes.getColumn(0, scratchVectorU);
@@ -7842,7 +7893,7 @@ class OrientedBoundingBox {
     }
 
     return distanceSquared;
-  }
+  } 
 
   computePlaneDistances(position, direction, result = [-0, -0]) {
     let minDist = Number.POSITIVE_INFINITY;
@@ -8529,8 +8580,11 @@ function createBox(box, transform, result) {
   const xAxis = transform.transformAsVector(origin.slice(0, 3));
   const yAxis = transform.transformAsVector(origin.slice(3, 6));
   const zAxis = transform.transformAsVector(origin.slice(6, 9));
-  const halfAxes = new Matrix3([xAxis[0], xAxis[1], xAxis[2], yAxis[0], yAxis[1], yAxis[2], zAxis[0], zAxis[1], zAxis[2]]);
-
+   const halfAxes = new Matrix3([xAxis[0], xAxis[1], xAxis[2], yAxis[0], yAxis[1], yAxis[2], zAxis[0], zAxis[1], zAxis[2]]);
+   //const halfAxes = new Matrix3([xAxis[0], xAxis[1], -xAxis[2], yAxis[0], yAxis[1], -yAxis[2], zAxis[0], zAxis[1], -zAxis[2]]);//改
+   //center.z *= -1//add
+  
+  
   if (defined$3(result)) {
     result.center = center;
     result.halfAxes = halfAxes;
@@ -8862,7 +8916,7 @@ class TilesetTraverser {
 
 
         // !zeg改 循环遍历子tile, maxDepth用来限制可加载的最大深度 
-      if (this.canTraverse(tile, frameState) && tile.depth < this.options.maxDepth) {//add maxDepth
+      if (this.canTraverse(tile, frameState) && (tile.depth < /* this.options. */maxDepth || tile.type != 'scenegraph' )) {//add maxDepth  是否继续遍历子集
         this.updateChildTiles(tile, frameState);
         shouldRefine = this.updateAndPushChildren(tile, frameState, stack, tile.hasRenderContent ? tile._selectionDepth + 1 : tile._selectionDepth);
       }
@@ -9187,10 +9241,19 @@ class TileHeader {
     _defineProperty(this, "_initialTransform", void 0);
 
     _defineProperty(this, "tilesetMatrix", void 0);//add
+ 
+    _defineProperty(this, "tileContent", void 0);//add
 
-
-
-
+    _defineProperty(this, "contentTransform", void 0);//add 
+    
+    _defineProperty(this, "volumeBox", void 0);//add 
+    
+    _defineProperty(this, "boundUntransformed", void 0);//add 
+     
+    _defineProperty(this, "rtcCenterState", rtcCenterGlobal);//add  初始时的状态,当mesh加载完检查下
+    
+     
+    
     this.header = header;
     this.tileset = tileset;
     this.id = extendedId || header.id;
@@ -9369,7 +9432,7 @@ class TileHeader {
     }
 
     try {
-      const contentUrl = this.tileset.getTileUrl(this.contentUrl);
+      const contentUrl = this.tileset.getTileUrl(this.contentUrl)+ `?_=${this.tileset.options.updateTime}` // !zeg改 添加version后缀  原:imageVersion
       const loader = this.tileset.loader;
       const options = { ...this.tileset.loadOptions,
         [loader.id]: { ...this.tileset.loadOptions[loader.id],
@@ -9380,7 +9443,7 @@ class TileHeader {
       this.content = await load(contentUrl, loader, options);
 
         // !zeg改
-        if (this.tileset.options.maxDepth < this.depth) {
+        if (/* this.tileset.options. */maxDepth < this.depth && this.type == 'scenegraph') {//有的场景depth为1的不是mesh,只是json,即实际最低depth>1
             this.unloadContent()
             return false
         }
@@ -9581,13 +9644,21 @@ class TileHeader {
   }
 
   _updateBoundingVolume(header) {
-      
-    let computedTransform = new Matrix4(this.tileset.modelMatrix).multiplyRight(this.computedTransform);  //add
-    //console.log('_updateBoundingVolume computedTransform', this.tileset.modelMatrix, computedTransform)  
-      
+    let computedTransform  
+    if(header.id == 'root_0' || !header.id){
+        console.log('root_0')  
+    }  
+    if(!this.tileset.lastRootTransform){//没事过后会因_updateTransform重算
+        computedTransform = new Matrix4(this.tileset.modelMatrix).multiplyRight(this.computedTransform);  //add
+    }else{
+        computedTransform = new Matrix4(new Matrix4$1().multiplyMatrices(this.tileset.lastRootTransform, this.getContentTransform()).elements)
+    }
+    
+ 
     this.boundingVolume = createBoundingVolume(header.boundingVolume, computedTransform/* this.computedTransform */, this.boundingVolume);
     const content = header.content;
-
+    
+ 
     if (!content) {
       return;
     }
@@ -9600,6 +9671,57 @@ class TileHeader {
       this._viewerRequestVolume = createBoundingVolume(header.viewerRequestVolume, computedTransform, this._viewerRequestVolume);
     }
   }
+   
+  
+  
+    getBoundUntransformed(){//add 这个会在mesh加载好后才会执行
+        if(!this.contentTransform){
+            console.error('?')
+        }
+        this.getContentTransform()
+         
+        let computedTransform2 = new Matrix4(this.contentTransform.elements)  
+
+        this.boundUntransformed = createBoundingVolume(this.header.boundingVolume, computedTransform2 , this.boundUntransformed);//add
+        
+        return  this.boundUntransformed
+        
+    }
+
+
+
+
+    getContentTransform(force){ //add 获取该tile在创建boundingVolume时需要的matrix,不包含最外层对整体模型的变换.
+        let rtcCenter, contentTransform
+        if(this.contentTransform && !force){//无需更新
+            return this.contentTransform.clone()
+        } 
+        
+        if(!this.tileset.tileTransInvert){
+            this.tileset.tileTransInvert = new Matrix4() 
+        }
+        
+        this.contentTransform = new Matrix4$1().fromArray(this.computedTransform).premultiply(new Matrix4$1().fromArray(this.tileset.tileTransInvert))
+
+        if(this.tileContent){ 
+            rtcCenter = this.content.rtcCenter 
+        }else{
+            rtcCenter = this.rtcCenterState
+        }
+      
+        if(!rtcCenter) {
+            let tranM = new Matrix4$1()  
+            tranM.makeScale(1,1,-1)//大部分是这种情况.  就是因为这个变换才加的这个函数,之前bounding没考虑这个不准。不知道为什么原生的代码不用scaleZ
+            this.contentTransform.premultiply(tranM) 
+        } 
+        //如果有rtcCenter的话一开始boundingVolume不准?会不会有显示问题?
+ 
+        return this.contentTransform.clone()
+    }
+
+
+
+
 
   _updateTransform(parentTransform = new Matrix4()) {
     const computedTransform = parentTransform.clone().multiplyRight(this.transform);
@@ -10269,7 +10391,7 @@ class Tileset3D extends EventDispatcher{//xzw add EventDispatcher
         const children = tile.header.children || [];
 
         // !zeg改  
-        if(tile.depth < this.options.maxDepth){                                     
+        if(tile.depth < /* this.options. */maxDepth){                                     
             for (const childHeader of children) {
               const childTile = new TileHeader(this, childHeader, tile);
               tile.children.push(childTile);
@@ -10277,7 +10399,7 @@ class Tileset3D extends EventDispatcher{//xzw add EventDispatcher
               stack.push(childTile);
             }
         }
-        window.maxDepth = Math.max(window.maxDepth||0,tile.depth)
+        window.maxTileDepth = Math.max(window.maxTileDepth||0,   tile.depth)
       }
     }
 
@@ -15852,6 +15974,7 @@ async function parseGLTF(gltf, arrayBufferOrString, byteOffset = 0, options, con
   const promise = decodeExtensions(gltf, options, context);
   promises.push(promise);
   await Promise.all(promises);
+  gltf.json.gltfArrayBuffer = arrayBufferOrString // !zeg add 兼容gltf
   return options !== null && options !== void 0 && (_options$gltf4 = options.gltf) !== null && _options$gltf4 !== void 0 && _options$gltf4.postProcess ? postProcessGLTF(gltf, options) : gltf;
 }
 
@@ -16996,37 +17119,69 @@ function loadersPlaneToMesh(plane) {
 }
 function loadersBoundingBoxToMesh(tile) {
     // Create a basic rectangle geometry from math.gl half-axes
-    const { boundingVolume } = tile;
-    let redColor = 0;
+    
+    
+    const boundUntransformed = tile.type == 'empty' ? tile.boundingVolume : tile.getBoundUntransformed() //empty时没创建好,直接给boundingVolume一样
+     
+    /* let redColor = 0;
     if (tile.content) {
         //redColor = Math.min((tile.content.byteLength != void 0 ? tile.content.byteLength : 0) / 500000, 1.0);
         redColor = Math.min( tile.depth / 10 , 1.0); //改
-    } 
-     
+    }  */
+    let hue = 0
+    if(tile.content){
+        hue = Math.min( tile.depth / 10 , 1.0); //改
+    }
 
-     
-    const boxColor = new Color(redColor, 1.0, 0.0);
+    const boxColor = new THREE.Color().setHSL(hue, 0.9, 0.85)
+    //const boxColor = new Color(redColor, 1.0, 0.0);
     const boxGeometry = new BoxGeometry(1, 1, 1);
     const boxTransform = new Matrix4$1();
-    if (boundingVolume.halfAxes) {
-        boxTransform.copy(getMatrix4FromHalfAxes(boundingVolume.halfAxes));
+    if (boundUntransformed.halfAxes) {
+        boxTransform.copy(getMatrix4FromHalfAxes(boundUntransformed.halfAxes));
     }
-    else if (boundingVolume.radius) {
-        boxGeometry.scale(boundingVolume.radius * 2, boundingVolume.radius * 2, boundingVolume.radius * 2);
+    else if (boundUntransformed.radius) {
+        boxGeometry.scale(boundUntransformed.radius * 2, boundUntransformed.radius * 2, boundUntransformed.radius * 2);
     }
     
-    boxTransform.premultiply((new Matrix4$1()).setPosition(...boundingVolume.center))  //add 
-    
+    boxTransform.premultiply((new Matrix4$1()).setPosition(...boundUntransformed.center))  //add 
     
+    /* if(tile.type != "empty"){ //root单独处理了
+        boxTransform.premultiply((new Matrix4$1()).makeScale(1,1,-1))//xzw  因为mesh倒转了所以box也 
+    }else{
+        console.log('empty')
+    } */
     boxGeometry.applyMatrix4(boxTransform);
-    
-    
     const edges = new EdgesGeometry(boxGeometry);
     const dispPlane = new LineSegments(edges, new LineBasicMaterial({ color: boxColor, transparent:true }));
     //dispPlane.position.copy(new Vector3$1(...boundingVolume.center));
     dispPlane.matrixAutoUpdate = false //add
+    let label = new Potree.TextSprite({
+        mat: new THREE.MeshBasicMaterial({transparent:true }), //depthTest:false会导致经常显示不出
+        backgroundColor: {r: 0, g: 0, b: 0, a:0.1},
+        textColor: {r: boxColor.r*255, g: boxColor.g*255, b: boxColor.b*255, a:0.9},
+        fontsize:100, 
+        //useDepth : true ,
+        renderOrder : 5, 
+        text: tile.id.split('/').pop().split('.b3dm')[0],   //Tile_+094_-010.b3dm'
+        name:'tile'   
+    })
+    label.addEventListener('mouseover',()=>{
+        if(label.sprite.material.opacity < 1)return
+        window.hoverTile = tile
+        console.log('hoverLabel',tile.id, tile._distanceToCamera)
+    })
+    /* let s = 0.6
+    label.scale.set(s,s,s) */
+    let s = tile.tileset.options.maximumScreenSpaceError / 400
+    label.scale.set(s,s,s)
     
     
+    dispPlane.add(label)
+     
+    label.position.set(...boundUntransformed.center)
+    //label.position.z *= -1
+    
     /* if(tile.content.byteLength == void 0){
         let oldUpdate = dispPlane.updateMatrixWorld.bind(dispPlane)
         dispPlane.updateMatrixWorld = (a,b)=>{
@@ -17041,7 +17196,7 @@ function loadersBoundingBoxToMesh(tile) {
     } */
     
     
-    
+    tile.volumeBox = dispPlane
     return dispPlane;
 }
 function getMatrix4FromHalfAxes(halfAxes) {
@@ -17416,7 +17571,8 @@ class Loader3DTiles {
                 updateTransforms: options.updateTransforms,
                 throttleRequests: options.throttleRequests,
                 maxRequests: options.maxRequests,
-                maxDepth: options.maxDepth || 50,  // !zeg改
+                updateTime: options.updateTime || 0, //add
+                //maxDepth: options.maxDepth || 50,  // !zeg改
                 contentLoader: (tile) => __awaiter(this, void 0, void 0, function* () {
                     let tileContent = null;
                     switch (tile.type) {
@@ -17431,8 +17587,9 @@ class Loader3DTiles {
                         }
                     }
                     if (tileContent) {
-                        tileContent.visible = false;
+                        tileContent.visible = false; 
                         renderMap[tile.id] = tileContent;
+                        tileContent.name = tile.id //add
                         root.add(renderMap[tile.id]);
                         if (options.debug) {
                             const box = loadersBoundingBoxToMesh(tile);
@@ -17466,10 +17623,10 @@ class Loader3DTiles {
                     }, '3d-tiles': {
                         loadGLTF: false
                     } }) }));
-            //
+            tileset.boxMap = boxMap //add
             // transformations
             const threeMat = new Matrix4$1();
-            const tileTrasnform = new Matrix4$1();
+            const tileTransform = new Matrix4$1();
             const rootCenter = new Vector3$1();
             let orientationDetected = false;
             if (tileset.root.boundingVolume) {
@@ -17479,7 +17636,7 @@ class Loader3DTiles {
                     console.warn("Cannot apply a model matrix to bounding volumes of type region. Tileset stays in original geo-coordinates.");
                     options.geoTransform = GeoTransform.WGS84Cartesian;
                 }
-                tileTrasnform.setPosition(tileset.root.boundingVolume.center[0], tileset.root.boundingVolume.center[1], tileset.root.boundingVolume.center[2]);
+                tileTransform.setPosition(tileset.root.boundingVolume.center[0], tileset.root.boundingVolume.center[1], tileset.root.boundingVolume.center[2]);
             }
             else {
                 console.warn("Bounding volume not found, no transformations applied");
@@ -17505,6 +17662,10 @@ class Loader3DTiles {
             root.updateMatrixWorld(true);
             const lastRootTransform = new Matrix4$1().copy(root.matrixWorld);
             const rootTransformInverse = new Matrix4$1().copy(lastRootTransform).invert();
+            tileset.lastRootTransform = lastRootTransform //add
+            
+            
+            
             detectOrientation(tileset.root);
             updateResetTransform();
             if (options.debug) {
@@ -17519,7 +17680,7 @@ class Loader3DTiles {
                 root.updateMatrixWorld(true);
             }
             else if (options.geoTransform == GeoTransform.WGS84Cartesian) {
-                root.applyMatrix4(tileTrasnform);
+                root.applyMatrix4(tileTransform);
                 root.updateMatrixWorld(true);
                 rootCenter.copy(root.position);
             }
@@ -17534,20 +17695,24 @@ class Loader3DTiles {
                 const rotation = new Euler().setFromRotationMatrix(orientationMatrix);
                 if (!rotation.equals(new Euler())) {
                     orientationDetected = true;
-                    const pos = new Vector3$1(tileTrasnform.elements[12], tileTrasnform.elements[13], tileTrasnform.elements[14]);
-                    tileTrasnform.extractRotation(orientationMatrix);
-                    tileTrasnform.setPosition(pos);
+                    const pos = new Vector3$1(tileTransform.elements[12], tileTransform.elements[13], tileTransform.elements[14]);
+                    tileTransform.extractRotation(orientationMatrix);
+                    tileTransform.setPosition(pos);
                     updateResetTransform();
                 }
             }
             function updateResetTransform() {
                 if (options.geoTransform != GeoTransform.WGS84Cartesian) {
                     // Reset the current model matrix and apply our own transformation
-                    threeMat.copy(tileTrasnform).invert();
-                    threeMat.premultiply(lastRootTransform);
-                    threeMat.copy(lastRootTransform).multiply(new Matrix4$1().copy(tileTrasnform).invert());
+                    //threeMat.copy(tileTransform).invert();
+                    //threeMat.premultiply(lastRootTransform); //xzw删 被下面copy这句覆盖了
+                    let tileTransInvert = new Matrix4$1().copy(tileTransform).invert()
+                    threeMat.copy(lastRootTransform).multiply(tileTransInvert);
                     tileset.modelMatrix = new Matrix4(threeMat.toArray());
                     //console.log('update tileset ModelMatrix', tileset.modelMatrix.elements)
+                     
+                    tileset.tileTransInvert = tileTransInvert.toArray() // add for volumebox
+                     
                 }
             }
             // 更新瓦片显隐和瓦片迭代更新                                  
@@ -17605,7 +17770,7 @@ class Loader3DTiles {
                                 if(visiVertexCount<maxVertexVisi){
                                     renderMap[tile.id].visible = true;
                                     visiVertexCount += renderMap[tile.id].vertexCount  //xzw add
-                                    options.debug && (boxMap[tile.id].material.opacity = 1)
+                                    options.debug && (boxMap[tile.id].material.opacity = 1 , boxMap[tile.id].children[0].sprite.material.opacity = 1 )
                                 }else{
                                     //console.log('超出', visiVertexCount)
                                 }
@@ -17620,7 +17785,7 @@ class Loader3DTiles {
                         if (renderMap[tile.id]) {
                             if(renderMap[tile.id].visible){
                                 renderMap[tile.id].visible = false;
-                                options.debug && (boxMap[tile.id].material.opacity = 0.1)
+                                options.debug && (boxMap[tile.id].material.opacity = 0.1, boxMap[tile.id].children[0].sprite.material.opacity = 0.1)
                                 
                                 visiVertexCount -= renderMap[tile.id].vertexCount  //xzw add
                             } 
@@ -17809,12 +17974,27 @@ class Loader3DTiles {
                             dracoLoader.dispose();
                         }
                     },   
+                    limit2lowestDepth: isLowest => {//zeg add   设置是否限制为最低精度tile深度  
+                       
+                        maxDepth = isLowest ? 1 : 100   //影响到shouldRefine, 检查方法:可以看到当maxDepth降低了之后viewer.objs.children[0].runtime.getTileset().tiles.filter(e=> e.tileContent.visible)变少
+                    
+                        if (cameraReference) {
+                            tileset._frameNumber++
+                            tilesetUpdate(tileset, renderMap, rendererReference, cameraReference)
+                        } 
+                    }, 
                 },                                                                             
                     
             };
         });
     }
 }
+
+
+
+
+
+
 function createGLTFNodes(gltfLoader, tile, unlitMaterial, options, rootTransformInverse) {
       
     return __awaiter(this, void 0, void 0, function* () {
@@ -17824,24 +18004,52 @@ function createGLTFNodes(gltfLoader, tile, unlitMaterial, options, rootTransform
             const shouldRotate = ((_a = tile.tileset.asset) === null || _a === void 0 ? void 0 : _a.gltfUpAxis) !== "Z";
             // The computed trasnform already contains the root's transform, so we have to invert it
             //const contentTransform = new Matrix4$1().fromArray(tile.computedTransform).premultiply(tileMatrix)//.premultiply(rootTransformInverse); //xzw 删。原先的会造成移动后tiles错乱
-            const contentTransform = new Matrix4$1().fromArray(tile.computedTransform).premultiply(tile.tileset.modelMatrix).premultiply(rootTransformInverse) 
-                // 这句同tile.computedTransform左乘tileTrasnform。  因为tileTrasnform拿不到所以使用modelMatrix。modelMatrix为tileTrasnform左乘rootTransform, 所以再左乘rootTransformInverse
-            
-            
+            //const contentTransform = new Matrix4$1().fromArray(tile.computedTransform).premultiply(tile.tileset.modelMatrix).premultiply(rootTransformInverse) 
+              
+              // 这句同tile.computedTransform左乘tileTransform。  因为tileTransform拿不到所以使用modelMatrix。modelMatrix为tileTransform左乘rootTransform, 所以再左乘rootTransformInverse
+             
             //改动:contentTransform中的computedTransform 去掉左乘 root.modelMatrixWorld , 因为移动过后这个computedTransform没更新
 
-            
-            
-            if (shouldRotate) {
-                contentTransform.multiply(rotateX); // convert from GLTF Y-up to Z-up
-            }
+             
             gltfLoader.parse(
                 tile.content.type == 'glTF' ? tile.content.gltf.gltfArrayBuffer : tile.content.gltfArrayBuffer,//tile.content.gltfArrayBuffer,
                 tile.contentUrl ? tile.contentUrl.substr(0, tile.contentUrl.lastIndexOf('/') + 1) : '', 
                 (gltf) => {
-                    const tileContent = gltf.scenes[0];
-                    //tileContent.applyMatrix4(contentTransform);
+                    const tileContent = gltf.scenes[0]; 
                     tileContent.vertexCount = 0   //xzw add
+                    tile.tileContent = tileContent //xzw add
+                     
+                    let needUpdate  
+                    if(tile.rtcCenterState != !!tile.content.rtcCenter){ // 等mesh加载好才知道rtcCenter,每个mesh坐标都不一样 
+                        needUpdate = true
+                        //console.error('rtcCenter有变化?!') 
+                    } 
+                     
+                    tile.rtcCenterState = rtcCenterGlobal = !!tile.content.rtcCenter
+                    
+                    let contentTransform = tile.getContentTransform(needUpdate)
+                    
+                    if(tile.content.rtcCenter){//大部分模型无 rtcCenter
+                        //console.error('rtcCenter有?!') //似乎bounding中包含这个信息了 所以getContentTransform不含这个
+                        let tranM = new Matrix4$1()   
+                        tranM.makeTranslation(tile.content.rtcCenter[0], tile.content.rtcCenter[1], tile.content.rtcCenter[2])
+                        contentTransform.premultiply(tranM)
+                    }
+                    
+                    if(needUpdate ){
+                        tile._updateBoundingVolume(tile.header) //add  重新更新
+                    }
+                       
+                    if (shouldRotate) { //大部分模型 无需 Rotate
+                        contentTransform.multiply(rotateX); // convert from GLTF Y-up to Z-up
+                    }
+                      
+                    tileContent.applyMatrix4(contentTransform);
+                    
+                    //'https://testgis.4dage.com/LVBADUI_qp/tileset.json', //村庄 这个案例是 要rotateX 且有rtcCenter的。boundingVolume已经是转换这两者后的值所以getContentTransform不加这个
+                    
+                    //tile总共要左乘的矩阵 rotateX -> tileTransInvert * computedTransform -> 对geometry的tranM修改 -> 整个模型的matrixWorld
+                    
                     tileContent.traverse((object) => {
                         if (object.type == "Mesh") {
                             const mesh = object;
@@ -17885,14 +18093,16 @@ function createGLTFNodes(gltfLoader, tile, unlitMaterial, options, rootTransform
                             
                             
                             //------------------add on 2023.1.16----zeg
-                            
-                            mesh.geometry.applyMatrix4(contentTransform)
-                            if (tile.content.rtcCenter) {
+                          
+                            //mesh.geometry.applyMatrix4(contentTransform)
+                            /* if (tile.content.rtcCenter) {
                                 // 有些b3dm模型会将坐标写在源码的rtcCenter里 如https://testgis.4dage.com/LVBADUI_qp/tileset.json 
                                 mesh.geometry.translate(tile.content.rtcCenter[0], tile.content.rtcCenter[1], tile.content.rtcCenter[2])
                             } else {
                                 mesh.geometry.scale(1, 1, -1) // 调整缩放,对应box也要进行变换(scaleZ对应box[2])
-                            }
+                            } */
+                            
+                            
                             //---------------------
                              
                         }
@@ -18016,7 +18226,7 @@ class tileHeader 也就是tileset里面的一个个tile 。  其上有.tileset
 
 
 
-tileset里算的tileTrasnform之后是不会改变的, tile.transform也是,是json里的。
+tileset里算的tileTransform之后是不会改变的, tile.transform也是,是json里的。
 
 tileset.modelMatrix  (通常这个值很大) 会随着位移改变
 tile.computedTransform   被我修改了,之前左乘了tileset.modelMatrix,现只包含了transform信息     _updateTransform(parentTransfor  其中有_updateBoundingVolume,这个影响可见性, 在computeVisibilityWithPlaneMask中计算
@@ -18033,8 +18243,26 @@ get isVisibleAndInRequestVolume() {
 
 显示所有tile似乎也不会卡顿. 但好像影响了加载顺序从而变慢了。visiVertexCount过量。 怀疑应该还是文件的bound有问题。
 原本会消失的地方虽然不会消失了但一直是模糊的
+
+
+
+=========
+访问所有tile:
+viewer.objs.children[0].runtime.getTileset().tiles
+它的mesh:   tile.tileContent
+或者直接得到所有mesh:   viewer.objs.children[0].children
+
+
+
+
+tile.depth最低为1 , root是0
+
+
+
  */
 
+ 
+
 
 
 

+ 33 - 34
libs/three.js/loaders/GLTFLoader.js

@@ -104,7 +104,7 @@ class GLTFLoader extends Loader {
         
         //路径相对于index.html  
         this.dracoLoader.setDecoderPath( urlPrefix + 'three.js/loaders/draco/'  /*or 'https://unpkg.com/three@0.144.0/examples/js/libs/draco/gltf/' 版本可升级 */) //这两个路径可以自己改。在laser的环境也要放一份这个路径
-        this.ktx2Loader.setTranscoderPath(urlPrefix + 'three.js/loaders/basic/' /*or 'https://unpkg.com/three@0.144.0/examples/js/libs/basis/' 版本可升级  */).detectSupport( renderer )
+        this.ktx2Loader.setTranscoderPath(urlPrefix + 'three.js/loaders/basis/' /*or 'https://unpkg.com/three@0.144.0/examples/js/libs/basis/' 版本可升级  */).detectSupport( renderer )
             
 	 
 
@@ -739,7 +739,7 @@ class GLTFMaterialsEmissiveStrengthExtension {
 	extendMaterialParams( materialIndex, materialParams ) {
 
 		const parser = this.parser;
-		const materialDef = parser.json.materials[ materialIndex ];
+		const materialDef = parser.json.materials[ materialIndex ] || parser.json.materials; //xzw change
 
 		if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
 
@@ -778,7 +778,7 @@ class GLTFMaterialsClearcoatExtension {
 	getMaterialType( materialIndex ) {
 
 		const parser = this.parser;
-		const materialDef = parser.json.materials[ materialIndex ];
+		const materialDef = parser.json.materials[ materialIndex ] || parser.json.materials;
 
 		if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) return null;
 
@@ -789,7 +789,7 @@ class GLTFMaterialsClearcoatExtension {
 	extendMaterialParams( materialIndex, materialParams ) {
 
 		const parser = this.parser;
-		const materialDef = parser.json.materials[ materialIndex ];
+		const materialDef = parser.json.materials[ materialIndex ]; //曾因这里报错加了一句  || parser.json.materials; 但是加载的图会先变白
 
 		if ( ! materialDef.extensions || ! materialDef.extensions[ this.name ] ) {
 
@@ -3254,6 +3254,7 @@ class GLTFParser {
 
 			const samplers = json.samplers || {};
 			const sampler = samplers[ textureDef.sampler ] || {};
+            Potree.Utils.makeTexDontResize(texture) //add
 /* //xzw 删除设置,因为已经makeTexDontResize
 			texture.magFilter = WEBGL_FILTERS[ sampler.magFilter ] || LinearFilter;
 			texture.minFilter = WEBGL_FILTERS[ sampler.minFilter ] || LinearMipmapLinearFilter;
@@ -3317,43 +3318,41 @@ class GLTFParser {
 		const promise = Promise.resolve( sourceURI ).then( function ( sourceURI ) {
 
 			return new Promise( function ( resolve, reject ) {
-                //为了防止chrome出现报错  The source image could not be decoded. 导致reject,重新写贴图加载方式: xzw
-
-                parser.textureLoader.load(sourceURI, (tex)=>{
-                    
-                    THREE.LinearMipmapLinearFilter //原本:NearestMipMapNearestFilter 闪烁
-                    //有一个block文件离远了有裂缝,只能使用LinearFilter,但是这样似乎更卡,且锯齿
-                    /* tex.minFilter = THREE.LinearFilter
-                    tex.generateMipmaps = false */
-                    
-                    
-                    
-                    Potree.Utils.makeTexDontResize(tex) 
-                    //console.log(tex.image.width, tex.image.height)
-                       
-                    resolve(tex) 
-                })  
-               
-                return;
-                 
-                
-				let onLoad = resolve;
-
-				if ( loader.isImageBitmapLoader === true ) {
+                if(json.asset.generator == 'gltfpack 0.18'){ //4dkk场景的模型
+ 
+                    let onLoad = resolve;
 
-					onLoad = function ( imageBitmap ) {
+                    if ( loader.isImageBitmapLoader === true ) {
 
-						const texture = new Texture( imageBitmap );
-						texture.needsUpdate = true;
+                        onLoad = function ( imageBitmap ) {
 
-						resolve( texture );
+                            const texture = new Texture( imageBitmap );
+                            texture.needsUpdate = true; 
 
-					};
+                            resolve( texture );
 
-				}
+                        };
 
-				loader.load( LoaderUtils.resolveURL( sourceURI, options.path ), onLoad, undefined, reject );
+                    }
 
+                    //loader.load( LoaderUtils.resolveURL( sourceURI, options.path ), onLoad, undefined, reject );
+                    let url = parser.textureLoader.manager.resolveURL( sourceURI, options.path )
+                    loader.load(url, onLoad, undefined, reject );
+                }else{
+                    //为了防止chrome出现报错  The source image could not be decoded. 导致reject,重新写贴图加载方式: xzw   //但不知道为何有的场景(如4dkk的)不成功
+                    parser.textureLoader.load(sourceURI, (tex)=>{ 
+                        THREE.LinearMipmapLinearFilter //原本:NearestMipMapNearestFilter 闪烁 有一个block文件离远了有裂缝,只能使用LinearFilter,但是这样似乎更卡,且锯齿
+                        /* tex.minFilter = THREE.LinearFilter
+                        tex.generateMipmaps = false */ 
+                         
+                        //console.log(tex.image.width, tex.image.height)
+                           
+                        resolve(tex) 
+                    },null,(e)=>{
+                        console.log('error load tex',e)
+                    })  
+                    
+                }
 			} );
 
 		} ).then( function ( texture ) {

+ 3 - 3
src/PotreeRendererNew.js

@@ -1363,7 +1363,7 @@ export class Renderer {
                     /* if(texture.image && !(texture.image instanceof Image) && !(texture instanceof THREE.CanvasTexture)){
                         //renderTarget的texture在创建renderTarget时已经初始化过 见setupRenderTarget
                         continue
-                    } */
+                    } */   
                      
 					if (!this.textures.has(texture) || texture.needsRebuild) {
 						let webglTexture = new WebGLTexture(gl, texture, this.threeRenderer);
@@ -1371,12 +1371,12 @@ export class Renderer {
 						this.textures.set(texture, webglTexture); 
                         delete texture.needsRebuild //renderTarget在resize后会触发dispose, 然后 _gl.deleteTexture( textureProperties.__webglTexture )所以需要重新建立
 					}  
-                    
+                     
 
 					let webGLTexture = this.textures.get(texture);
 					webGLTexture.update();
 
-
+ 
 				}
 			}
 		}

+ 28 - 30
src/custom/mergeStartTest.js

@@ -280,9 +280,9 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
         
         
         modelEditing.dispatchEvent("position_changed")
-         
+          
     }
-    let cancelMove = ()=>{ 
+    let cancelMove = ()=>{  
         modelEditing = null
         viewer.removeEventListener('global_mousemove', moveModel); 
         viewer.removeEventListener('global_click', confirmPos); 
@@ -292,15 +292,15 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
         cancelMove()  
         return {stopContinue:true}
     }
-    
-    
+          
+       
     let focusOnSelect = (object, duration = 400)=>{ 
-         
+          
         let boundingBox = object.boundingBox.clone().applyMatrix4(object.matrixWorld)
         let center = boundingBox.getCenter(new THREE.Vector3)
         let size = boundingBox.getSize(new THREE.Vector3) 
         let maxSize = size.length() //对角线长度
-        
+         
         if(object.isPointcloud){
             maxSize /= 2
         }
@@ -318,14 +318,15 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
     viewer.setControls(viewer.orbitControls) 
      
       
-          
-      
-    let tilesetUrls = [ 
-    
-        'https://4dkk.4dage.com/scene_view_data/SG-t-hFdFM1eCYs6/images/3dtiles/tileset.json?_=1716879888240',
+             
+         
+    let tilesetUrls = [   
+        'https://testgis.4dage.com/LVBADUI_qp/tileset.json', //村庄   含rtcCenter      
+        'http://4dkk.4dage.com/fusion/test/b3dm/modelId_1075/tileset.json', //depth 11 较高  ,为了防止卡顿需要提高maximumScreenSpaceError
+        //'https://4dkk.4dage.com/scene_view_data/SG-t-hFdFM1eCYs6/images/3dtiles/tileset.json?_=1716879888240',
         //(`scene_view_data/{num}/images/3dtiles/tileset.json?_=${Date.now()}`),
-        'https://4dkk.4dage.com/fusion/test/b3dm/tileset.json',  //高层小区
-        'https://testgis.4dage.com/LVBADUI_qp/tileset.json', //村庄
+        'https://4dkk.4dage.com/fusion/test/b3dm/tileset.json',  //高层小区  模型无问题
+        
         'https://4dkk.4dage.com/fusion/testb3dm/modelId_613/tileset.json',//"952.16MB"  港一
         'https://4dkk.4dage.com/fusion/testb3dm/modelId_609/tileset.json',//618.37MB  田野 'https://4dkk.4dage.com/fusion/test/b3dmtest001/tileset.json',
         'https://4dkk.4dage.com/fusion/test/model/modelId_614/tileset.json',//172.97MB 国家电网 //'https://4dkk.4dage.com/fusion/test/model/modelId_602/tileset.json',
@@ -348,7 +349,7 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
         let loadDone = (model)=>{ 
             if(isFirstLoad){
                 modelEditing = model; 
-                MergeEditor.setModelBtmHeight(model, 0) //默认离地高度为0                
+      //          MergeEditor.setModelBtmHeight(model, 0) //默认离地高度为0                
                 /* if(name == '3dTiles'){
                     setTimeout(()=>{
                         moveModel({pointer:{x:0,y:0}}) //3dTiles的移动会错乱,先默认放在当前视图中间吧 
@@ -366,7 +367,7 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                 let updateBound = ()=>{ 
                     model.updateMatrixWorld()
                     viewer.updateModelBound() 
-                }  
+                }    
                 let maintainBtmZAndCenter = ()=>{
                     MergeEditor.maintainBoundXY(model)
                     MergeEditor.setModelBtmHeight(model) 
@@ -501,7 +502,7 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                 var path = `${Potree.resourcePath}/models/obj/`
                 viewer.loadModel({
                     name, 
-                    objurl: path+ 'sphere.obj' /* 'GW1H.obj' */,  //解析时间4.392s
+                    objurl: path+ 'chuizi.obj' /* 'GW1H.obj' */,  //解析时间4.392s
                     //mtlurl: path+'GW1H.mtl',    
                     transform : { 
                         rotation : [0,  0,   0],
@@ -576,7 +577,7 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
                     url: url || tilesetUrls[tileIndex++],
                      
                     transform : { 
-                        rotation : [Math.PI/2,  0,   0],
+                        rotation : [0,  0,   0],
                         position : [0,0,0]  
                     }  
                 },callback,onprogress)
@@ -713,6 +714,8 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
            MergeEditor.transformControls.mode = 'rotate'
         }else if(e.event.key == "w"){
             MergeEditor.transformControls.mode = 'translate'
+        }else if(e.event.key == "s"){
+            MergeEditor.transformControls.mode = 'scale'
         }
     })
      
@@ -739,19 +742,14 @@ var start = function(dom, mapDom, number, fileServer, webSite){ //t-Zvd3w0m
         
     },2000)  */  
     
-    setTimeout(()=>{
-    
-    
-        Potree.addModel('laser')
-        /* setTimeout(()=>{ 
-            Potree.addModel('glb')
-        },100) */
-        
-        /* viewer.addEventListener('modelLoaded',(e)=>{ 
-            confirmPos() 
-        }) */ 
-        
-    },2000)
+     setTimeout(()=>{
+         Potree.addModel('3dTiles')
+         viewer.addEventListener('modelLoaded',(e)=>{
+             
+                confirmPos()
+             
+        }) 
+     },2000)
 }
  
  

+ 2 - 0
src/custom/modules/mergeModel/MergeEditor.js

@@ -587,6 +587,8 @@ let MergeEditor = {
         if(z == void 0) z = model.btmHeight; //维持离地高度
         else model.btmHeight = z;
         
+        if(model.btmHeight == void 0)return
+        
         model.updateMatrixWorld()
         let boundingBox2 = model.boundingBox.clone().applyMatrix4(model.matrixWorld)
         let size = boundingBox2.getSize(new THREE.Vector3);

+ 7 - 7
src/custom/modules/volumeCompute/Prism.js

@@ -95,16 +95,16 @@ export class Prism extends Measure{
         }
         //console.log(this.horizonZ)
         
-    }
-    
-    setBaseModel(model){
+    } 
+     
+    setBaseModel(model, modelHaventLoad){//三种状态:使用model、使用基准高度、 什么都没有(不允许计算、不高亮、等待模型上传)
         this.baseModel = model
-      
-        Potree.Utils.updateVisible(this.areaPlane,'useBaseModel',!model)
+        this.modelHaventLoad = modelHaventLoad
+        Potree.Utils.updateVisible(this.areaPlane,'unuseHorizonH',!model && !modelHaventLoad)
     }
-    
+     
     setClipBox(boxes){//clipBoxes_out
-        this.clipBoxes = boxes || []
+        this.clipBoxes = boxes || [] 
     }
     
    

+ 6 - 3
src/custom/modules/volumeCompute/VolumeComputer.js

@@ -485,11 +485,14 @@ export default class VolumeComputer extends THREE.EventDispatcher{
         return {w,h,pxPerMetric, cW,cH}
         
         
-    }
-    
+    } 
+     
     //法1:只用一个顶部相机(当挖方遮挡填方时不准,但好算)
     async compute(prism, deferred_, getResolveResult){
-        if(!prism)return console.log('无prism?') 
+        if(!prism || prism.modelHaventLoad){
+            console.log('prism有问题') 
+            return deferred_.reject() 
+        }
         if(this.computingObject) return console.log('正在计算,请稍等')
              
         let oldCurPrism = this.currentPrism

+ 1 - 1
src/custom/objects/TextSprite.js

@@ -196,7 +196,7 @@ export class TextSprite extends THREE.Object3D{
 		context.canvas.height = spriteHeight;
 		context.font = this.fontWeight + ' ' + this.fontsize * r + 'px ' + this.fontface; 
         
-        if(spriteWidth>1000){
+        if(spriteWidth>4000){
             console.error('spriteWidth',spriteWidth,'spriteHeight',spriteHeight,this.fontsize,r,this.text,margin)
         }
  

+ 7 - 5
src/custom/objects/tool/Measure.js

@@ -233,13 +233,15 @@ export class Measure extends ctrlPolygon{
             { // coordinate labels
                 let coordinateLabel = this.coordinateLabels[0];
                 
-                let lonlat = viewer.transform.lonlatToLocal.inverse(position.toArray())
-                let EPSG4550 = viewer.transform.lonlatTo4550.forward(lonlat)
                 let pos = [
-                    position.toArray(),
-                    lonlat,
-                    EPSG4550
+                    position.toArray()
                 ] 
+                if(viewer.transform){
+                    let lonlat = viewer.transform.lonlatToLocal.inverse(position.toArray())
+                    let EPSG4550 = viewer.transform.lonlatTo4550.forward(lonlat)
+                    pos.push(lonlat,EPSG4550)
+                }
+                           
                 //let msg = position.toArray().map(p => Utils.addCommas(p.toFixed(2))).join(" / ");
                 let msg = pos.map(a=> 
                      a.map(p => Utils.addCommas(p.toFixed(10))).join(", ") 

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

@@ -232,13 +232,15 @@ export class ctrlPolygon extends THREE.Object3D {
                 
                
                 if(this.points_datasets){
-                    if(e.intersect.pointcloud) this.points_datasets[i] = e.intersect.pointcloud.dataset_id
-                    else if(e.intersect.object) this.points_datasets[i] = e.intersect.object.dataset_id
-                    else{ 
-                        if(this.measureType == 'MulDistance Ring'){//因为它的每个point跟着各自的dataset走,而不是整体的dataset
-                            let pointcloud = viewer.findClosestDatasetOnMap(I) || viewer.scene.pointclouds[0]
-                            this.points_datasets[i] = pointcloud.dataset_id
-                        }else this.points_datasets[i] = null
+                    if(e.intersect){
+                        if(e.intersect.pointcloud) this.points_datasets[i] = e.intersect.pointcloud.dataset_id
+                        else if(e.intersect.object) this.points_datasets[i] = e.intersect.object.dataset_id
+                        else{ //地图
+                            if(this.measureType == 'MulDistance Ring'){//因为它的每个point跟着各自的dataset走,而不是整体的dataset
+                                let pointcloud = viewer.findClosestDatasetOnMap(I) || viewer.scene.pointclouds[0]
+                                this.points_datasets[i] = pointcloud.dataset_id
+                            }else this.points_datasets[i] = null
+                        }
                     }
                 }
             }

+ 1 - 1
src/custom/potree.shim.js

@@ -1611,7 +1611,7 @@ Potree.numVisiblePoints = 0
     HQSplatRenderer.prototype.init = function(){
         oldInit()
         viewer.addEventListener('resize',this.resize.bind(this))
-    }
+    } 
     
     HQSplatRenderer.prototype.resize = function(e){
 		this.rtDepth.setSize(e.canvasWidth, e.canvasHeight);

+ 1 - 1
src/custom/three.shim.js

@@ -202,7 +202,7 @@ THREE.EventDispatcher.prototype.dispatchEvent = function(event){
         }
 
     }
-}
+} 
 
 THREE.EventDispatcher.prototype.traverse = function(callback){ 
     let result = callback( this );

+ 11 - 4
src/custom/utils/DrawUtil.js

@@ -11,12 +11,19 @@ import {Features} from "../../Features.js";
 var defaultColor = new THREE.Color(1,1,1);//config.applicationName == "zhiHouse" ? Colors.zhiBlue : Colors.lightGreen;
 
 function dealPosArr(points){//识别是否每个点都不一样,把连续点变为不连续的片段连接 
-    if(points.length > 2 && !points[2].equals(points[1])){
+    let add = (points)=>{
         let points2 = [] , len = points.length 
         for(let i=0;i<len-1;i++){
             points2.push(points[i], points[i+1])
         } 
-        return points2
+        return points2  
+    }
+    if(points[0] && points[0] instanceof Array){//多组,每组间连续,但组之间不连续
+        let points2 = []
+        points.forEach(ps=>points2.push(...add(ps)))
+        return points2   
+    }else if(points.length > 2 && !points[2].equals(points[1])){
+        return add(points)
     }else return points
     
 } 
@@ -55,7 +62,7 @@ var LineDraw = {
     
 	moveLine: function (line, posArr) {
         //if(posArr.length == 0)return
-        if(!line.uncontinuous)posArr = dealPosArr(posArr)
+        if(!line.uncontinuous || posArr[0] && posArr[0] instanceof Array)posArr = dealPosArr(posArr)
         let position = []
         posArr.forEach(e=>position.push(e.x,e.y,e.z))
         line.geometry.setAttribute('position', new THREE.Float32BufferAttribute(/* new Float32Array( */position/* ) */, 3));
@@ -127,7 +134,7 @@ var LineDraw = {
 	moveFatLine: function(line, posArr){
 		var geometry = line.geometry;
         var positions = [];
-        line.uncontinuous || (posArr = dealPosArr(posArr))
+        if(!line.uncontinuous || posArr[0] && posArr[0] instanceof Array) posArr = dealPosArr(posArr) 
         posArr.forEach(e=>{positions.push(...e.toArray())})
          
 		 

+ 21 - 17
src/custom/viewer/ViewerNew.js

@@ -2838,7 +2838,7 @@ export class Viewer extends ViewerBase{
             let clipBoxes_out = clipBoxes.filter(e=>e.box.clipTask == ClipTask.SHOW_OUTSIDE && !e.box.highlight)
             let highlightBoxes = clipBoxes.filter(e=>e.box.highlight )
 			//let prismPolygons = this.modules.volumeComputer && this.modules.volumeComputer.entered ? viewer.scene.measurements.filter(e=>(e.measureType == 'MulDistance Ring') && !e.isNew) : []
-			let prismPolygons = this.modules.volumeComputer ? this.modules.volumeComputer.prisms.filter(e=>!e.isNew && e.visible && !e.dontHighlight) : []
+			let prismPolygons = this.modules.volumeComputer ? this.modules.volumeComputer.prisms.filter(e=>!e.isNew && e.visible && !e.dontHighlight && (e.baseModel || !e.modelHaventLoad)) : []
             
             // set clip volumes in material
 			for(let pointcloud of visiblePointClouds){
@@ -5167,7 +5167,7 @@ export class Viewer extends ViewerBase{
             }   
         }
         
-        object.name = fileInfo_.name != void 0 ? fileInfo_.name : fileInfo_.type
+        object.name = fileInfo_.name != void 0 ? fileInfo_.name : fileInfo_.fileType
         object.fileType = fileInfo_.fileType
         object.boundingBox = boundingBox  //未乘上matrixWorld的本地boundingBox
         //object.scale.set(1,1,1);//先获取原始的大小时的boundingBox
@@ -5300,6 +5300,10 @@ export class Viewer extends ViewerBase{
         done && done(object, fileInfo_)
             
         this.dispatchEvent({type:'modelLoaded',model:object})
+        
+        
+        
+        //如果需要点击出现transform工具需要它有select事件 如 viewer.objs.children[1].addEventListener('select',()=>{})
     }
     
     
@@ -5378,29 +5382,29 @@ export class Viewer extends ViewerBase{
                     object = new THREE.Points(geometry, new THREE.PointsMaterial({vertexColors:true, size:0.02})) 
                     //141M的点云,intersect费时300ms以上
                 }else{//mesh
-                    object = new THREE.Mesh(geometry) 
-                }
+                    object = new THREE.Mesh(geometry)    
+                }       
                 loadDone(object)
             })
             
-        }else if(fileInfo.fileType == '3dTiles'){
-             
+        }else if(fileInfo.fileType == '3dTiles'){ 
+                       
             let result = await Loader3DTiles.load({
-                url: fileInfo.url,
+                url: fileInfo.url, 
                 gltfLoader : loaders.glbLoader, 
-                //renderer: SceneRenderer.renderer  
-                options: {
+                //renderer: SceneRenderer.renderer   
+                options: {    
                     //dracoDecoderPath: '../utils/loaders/DRACOLoader/draco',
                     //basisTranscoderPath: '../utils/loaders/KTX2Loader/basis',
-                    maximumScreenSpaceError: 30,  //如果本身tiles很密很小这个值就不能很大。
+                    maximumScreenSpaceError: fileInfo.maximumScreenSpaceError || 80,  //越小越清晰。           如果本身tiles很密很小这个值就不能很大。
                     //maxDepth: 100, 
                     maximumMemoryUsage: 200, //缓存大小。单位M(但实际结果是 2.5*maximumMemoryUsage + 750  。超过2G会崩, 所以应该小于540) 若太小,密集的tile反复加载很卡. (任务管理器刷新网页后若内存不掉就要结束进程否则虚高)
-                    //debug:true,
-                    parent: this.scene.scene,
-                    is4dkk: fileInfo.is4dkk,//是否是4dkk中的模型
+                    //debug:true, //show box  
+                    parent: this.scene.scene, 
+                    is4dkk: fileInfo.is4dkk,//是否是4dkk中的模型. 通常maximumScreenSpaceError需要10
                     updateTime: fileInfo.updateTime, //加后缀防止缓存
-                },
-            })
+                },  
+            })  
             console.log(result)
             result.model.runtime = result.runtime
  
@@ -5423,13 +5427,13 @@ export class Viewer extends ViewerBase{
                 let vi = true
                 Object.defineProperty( result.model, "visible", {
                     get: function() {
-                        return vi
+                        return vi 
                     },
                     set: function(v) {
                         vi = v 
                         tileset.visible = v;  //同步,使不加载
                         tileset.nextForceUpdate = true
-                    }
+                    }  
                 })  
             } 
             

+ 1 - 1
src/custom/viewer/map/Map.js

@@ -261,7 +261,7 @@ export class TiledMapBase extends THREE.EventDispatcher{
     
     
     updateObjectGroup(){
-        this.position && this.objectGroup.position.copy(this.position),
+        this.position && this.objectGroup.position.copy(this.position).setZ(0),
         this.quaternion && this.objectGroup.quaternion.copy(this.quaternion),
         this.objectGroup.updateMatrixWorld(!0)
     }

+ 84 - 24
src/loader/ShapefileLoader.js

@@ -4,28 +4,35 @@ import {Line2} from "../../libs/three.js/lines/Line2.js";
 import {LineGeometry} from "../../libs/three.js/lines/LineGeometry.js";
 import {LineMaterial} from "../../libs/three.js/lines/LineMaterial.js";
 
+import {LineDraw} from "../custom/utils/DrawUtil.js"; 
+
 export class ShapefileLoader{
 
 	constructor(){
 		this.transform = null;
 	}
 
-	async load(path){
+	async load(path, color){
 
 		const matLine = new LineMaterial( {
-			color: 0xff0000,
-			linewidth: 3, // in pixels
+			color: color || 0xff0000,
+			lineWidth: 3, // in pixels
 			resolution:  new THREE.Vector2(1000, 1000),
 			dashed: false
 		} );
 
+ 
+
 		const features = await this.loadShapefileFeatures(path);
 		const node = new THREE.Object3D();
 		
-		for(const feature of features){
+        
+        let jump = 0 
+		for(const feature of features){//5是碎的
+            //if(feature.geometry.type!= 'MultiLineString' || ++jump != 5) continue
 			const fnode = this.featureToSceneNode(feature, matLine);
-			node.add(fnode);
-		}
+			fnode && node.add(fnode);
+		} 
 
 		let setResolution = (x, y) => {
 			matLine.resolution.set(x, y);
@@ -41,6 +48,8 @@ export class ShapefileLoader{
 	}
 
 	featureToSceneNode(feature, matLine){
+        //console.log(feature)
+        
 		let geometry = feature.geometry;
 		
 		let color = new THREE.Color(1, 1, 1);
@@ -50,7 +59,7 @@ export class ShapefileLoader{
 			transform = {forward: (v) => v};
 		}
 		
-		if(feature.geometry.type === "Point"){
+		if(geometry.type === "Point"){
 			let sg = new THREE.SphereGeometry(1, 18, 18);
 			let sm = new THREE.MeshNormalMaterial();
 			let s = new THREE.Mesh(sg, sm);
@@ -96,6 +105,37 @@ export class ShapefileLoader{
 			line.position.copy(min);
 			
 			return line;
+		}else if(geometry.type === "MultiLineString"){//xzw add  江门的那个文件
+			let coordinates = [];
+			//console.warn('MultiLineString') //多组连续线段,组之间不连续
+			let min = new THREE.Vector3(Infinity, Infinity, Infinity);
+			for(let i = 0; i < geometry.coordinates.length; i++){ 
+                let points = geometry.coordinates[i]; //有时候是两个点有时候多个
+                let coordinateSlice = []
+                points.forEach(point=>{
+                    let [long, lat] = point;
+                    let pos = transform.forward([long, lat]);
+                    min.x = Math.min(min.x, pos[0]);
+                    min.y = Math.min(min.y, pos[1]);
+                    min.z = Math.min(min.z, 20);
+                    coordinateSlice.push(new THREE.Vector3(pos[0], pos[1], 20));
+                }) 
+                coordinates.push(coordinateSlice)        
+			}
+			 
+            coordinates.forEach(coordinateSlice=> coordinateSlice.forEach(point=>point.sub(min) ))
+                   
+            let line = LineDraw.createFatLine(coordinates,{
+                uncontinuous: true,
+                mat:matLine
+                /* color: 0xff0000,
+                dashSize: 0.5, 
+                gapSize: 0.2, 
+                lineWidth: config$1.measure.lineWidth,  */
+            });
+            line.position.copy(min);
+			
+			return line;
 		}else if(geometry.type === "Polygon"){
 			for(let pc of geometry.coordinates){
 				let coordinates = [];
@@ -132,28 +172,48 @@ export class ShapefileLoader{
 				return line;
 			}
 		}else{
-			console.log("unhandled feature: ", feature);
+			console.log("unhandled feature: ",  geometry.type);
 		}
+        
+        
+        
+        
+        
+        function getLine(coordinates){
+            
+        }
 	}
 
 	async loadShapefileFeatures(file){
 		let features = [];
-
-		let source = await shapefile.open(file);
-
-		while(true){
-			let result = await source.read();
-
-			if (result.done) {
-				break;
-			}
-
-			if (result.value && result.value.type === 'Feature' && result.value.geometry !== undefined) {
-				features.push(result.value);
-			}
-		}
-
-		return features;
+        if(file.split('.').pop() == 'shp'){
+            let source = await shapefile.open(file);
+            
+            while(true){
+                let result = await source.read();
+
+                if (result.done) {
+                    break;
+                }
+
+                if (result.value && result.value.type === 'Feature' && result.value.geometry !== undefined) {
+                    features.push(result.value);
+                }
+            }
+            return features;
+        }else if(file.split('.').pop() == 'json'){
+            return new Promise((resolve,reject)=>{
+                Potree.loadFile(file, {/* returnText:true */} , (data)=>{
+                    
+                     
+                    console.log(data);
+                    resolve(data.features)
+                    
+                 });
+            }) 
+            
+        }
+		
 	}
 
 };

+ 1 - 1
src/navigation/FirstPersonControlsNew.js

@@ -507,7 +507,7 @@ export class FirstPersonControls extends THREE.EventDispatcher {
             let rotCenter2d, rotCenter
             if(rotAroundPoint){
                 let pivotType = this.target ? 'target' : viewer.atDatasets.length > 0 ? 'intersect' :  viewer.inputHandler.selection.length ? 'selection' : this.target2 ? 'target2' : 'boundCenter'  
-                rotCenter = pivotType == 'target'? this.target :pivotType == 'intersect' ? intersect.location : pivotType == 'selection' ? viewer.inputHandler.selection[0].position : pivotType == 'target2' ? this.target2 :viewer.bound.center
+                rotCenter = pivotType == 'target'? this.target :pivotType == 'intersect' ? intersect.location : pivotType == 'selection' ? viewer.inputHandler.selection[0].position : pivotType == 'target2' ? this.target2 : viewer.bound && viewer.bound.center
                 if(rotCenter){
                     rotCenter2d = rotCenter.clone().project(e.dragViewport.camera) //点在屏幕中的位置。   若z>1 则在背面 或 超出far范围 
                 }else{

+ 43 - 12
src/utils/TransformationToolNew.js

@@ -734,7 +734,8 @@ export class TransformationTool extends THREE.EventDispatcher{
 		let I = ray.intersectPlane(drag.dragPlane, new THREE.Vector3());
 
 		if (I) {
-			let center = this.scene.getWorldPosition(new THREE.Vector3());
+           
+			let center = this.scene.getWorldPosition(new THREE.Vector3()); //bounding中心
 			let from = drag.pivot;
 			let to = I;
 
@@ -749,13 +750,31 @@ export class TransformationTool extends THREE.EventDispatcher{
 			}
             let matrixBefore = this.selection[0].matrix.clone()
 			let normal = new THREE.Vector3(...handle.alignment);
-			for (let selection of this.selection) {
-				selection.rotateOnAxis(normal, angle);
+			for (let selection of this.selection) { 
+				//直接修改matrix,使整体绕boundingBox中心旋转。 xzw
+              
+                let quaternion = selection.quaternion.clone()
+                let diffQua = new THREE.Quaternion().setFromAxisAngle( normal, angle )//变化量,参考 selection.rotateOnAxis(normal, angle);
+                
+                let moveToZero = new THREE.Matrix4().setPosition(center.clone().negate()) //先将boundingBox中心(整体)移动到原点
+                let rotM = new THREE.Matrix4().makeRotationFromQuaternion(quaternion.clone().inverse().premultiply(diffQua).premultiply(quaternion) );//再旋转。根据selection.rotateOnAxis,应该是旧的qua 右乘 diffQua,所以先用invert消掉旧的qua
+                let moveBack = new THREE.Matrix4().setPosition(center.clone())//移动回去,使boundingBox中心位置还原
+                
+                selection.matrix.premultiply(moveToZero).premultiply(rotM).premultiply(moveBack)
+                selection.matrix.decompose(selection.position, selection.quaternion, selection.scale)//记录  (scale基本不变)
+                 
+                 
+                 
+                
                 selection.updateMatrixWorld();//xzw add 保险起见立即update
 				selection.dispatchEvent({
 					type: "orientation_changed",
 					object: selection
 				});
+                selection.dispatchEvent({//当boundingBox中心不在原点时
+					type: "position_changed",
+					object: selection
+				});
 			}
             this.dispatchEvent({type:'transformed', changeType: ['orientation'], matrixBefore })//add
 			drag.pivot = I;
@@ -775,11 +794,11 @@ export class TransformationTool extends THREE.EventDispatcher{
 		
         if(handle && handle.name.includes('translation') && this.selection[0]){
         
-            let posWorld = this.selection[0].getWorldPosition(new THREE.Vector3()); //是需要世界坐标吗
+            let posWorld = this.scene.getWorldPosition(new THREE.Vector3())//bounding中心
                 
             if(!drag.intersectionStart){
                 drag.intersectionStart = drag.location;
-                drag.worldPositionStart = posWorld
+                drag.worldPositionStart = this.selection[0].getWorldPosition(new THREE.Vector3()); 
                   
                  
                 drag.objectQua = this.selection[0].quaternion.clone()//不考虑父级
@@ -941,15 +960,22 @@ export class TransformationTool extends THREE.EventDispatcher{
 					dragDirectionOS.set(0, 0, 0);
 				}
 				let dragDirection = dragDirectionOS.dot(new THREE.Vector3(...handle.alignment));
-
+                let alignment = new THREE.Vector3(...handle.alignment)
 				let diff = new THREE.Vector3().subVectors(iOnLine, drag.pivot);
-				let diffScale = new THREE.Vector3(...handle.alignment).multiplyScalar(diff.length() * direction * dragDirection);
-				let diffPosition = diff.clone().multiplyScalar(0.5);
-   
- 
+				let diffScale = alignment.clone().multiplyScalar(diff.length() * direction * dragDirection);
+				//let diffPosition = diff.clone().multiplyScalar(0.5); //这个仅当bound包含原点才准确。
+             
                 let matrixBefore = this.selection[0].matrix.clone()
 				for (let selection of this.selection) {
-                    //xzw 改:否则不跟手
+                    //xzw 改:否则不跟手   
+                    
+                    let {min,max} = selection.boundingBox
+                    let fixPoint = alignment.x != 0 ? (alignment.x > 0 ? min : max).clone().setY(0).setZ(0) :   //要保证另一边不能移动   
+                                alignment.y != 0 ? (alignment.y > 0 ? min : max).clone().setX(0).setZ(0) :
+                                                    (alignment.z > 0 ? min : max).clone().setX(0).setY(0) 
+                    
+                    let fixPointBefore = fixPoint.clone().applyMatrix4(selection.matrixWorld)
+                
                     let size = selection.boundingBox.getSize(new THREE.Vector3) 
                     let diffScale_ = diffScale.clone().divide(size)
                     
@@ -959,7 +985,12 @@ export class TransformationTool extends THREE.EventDispatcher{
                      
 					selection.scale.add(diffScale_); 
                     selection.scale.max(new THREE.Vector3(0.1,0.1,0.1))  
-					selection.position.add(diffPosition);
+					//selection.position.add(diffPosition);
+                    selection.updateMatrixWorld();
+                    
+                    
+                    let fixPointAfter = fixPoint.clone().applyMatrix4(this.selection[0].matrixWorld)
+                    selection.position.sub(new THREE.Vector3().subVectors(fixPointAfter,fixPointBefore))//保证另一边不能移动所需要的位移
                     selection.updateMatrixWorld();//xzw add 保险起见立即update
                     
 					selection.dispatchEvent({

+ 1 - 1
src/viewer/potree.css

@@ -826,7 +826,7 @@ body{
     white-space: nowrap;
     font-size: 12px;
     font-style: normal;
-    pointer-events: auto;
+    /* pointer-events: auto; */
     background-repeat: no-repeat;
     background-size: 100% 100%;
     background: #02c1add4;