jinx пре 11 месеци
родитељ
комит
3c37f15212

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


Разлика између датотеке није приказан због своје велике величине
+ 1 - 1
public/js/3.js


Разлика између датотеке није приказан због своје велике величине
+ 1 - 1
public/js/5.js


Разлика између датотеке није приказан због своје велике величине
+ 1 - 1
public/js/chunk-vendors.js


Разлика између датотеке није приказан због своје велике величине
+ 2 - 2
public/js/smart.js


+ 353 - 84
public/static/lib/potree/potree.js

@@ -4318,8 +4318,8 @@
 	    }
 	  },
 	  adjustSpeed: function adjustSpeed(e, t) {
-	    for (var u = this.getById(e), duration = 0; duration < u.length; duration++) {
-	      var r = u[duration];
+	    for (var u = this.getById(e), n = 0; n < u.length; n++) {
+	      var r = u[n];
 	      r.duration /= t, r.current /= t;
 	    }
 	  },
@@ -4593,8 +4593,12 @@
 	  },
 	  replaceAll: function replaceAll(str, f, e) {
 	    //f全部替换成e
+
+	    /* if(str.replaceAll ) return str.replaceAll(f, e)
+	    else{ */
 	    var reg = new RegExp(f, "g"); //创建正则RegExp对象  
-	    return str.replace(reg, e);
+	    return str.replace(reg, e); //str.split(f).join(e);
+	    //}
 	  },
 	  dealURL(url) {
 	    var urlNew = this.replaceAll(url, "\\+", "%2B"); // 浏览器似乎不支持访问带+的地址
@@ -4875,6 +4879,46 @@
 	    context.clearRect(0, 0, canvas.width, canvas.height);
 	    return dataUrl;
 	  },
+	  /* changeShaderToWebgl2(vs, fs, matType, otherReplaces=[]){//部分shader要根据webgl版本作更改
+	      if(!Potree.settings.isWebgl2)return {vs, fs}
+	      let turnTo300 = matType != 'ShaderMaterial' && (vs.includes('gl_FragDepthEXT') || fs.includes('gl_FragDepthEXT') ) 
+	      let addV300 = turnTo300 && matType != 'RawShaderMaterial' // RawShaderMaterial直接material.glslVersion = '300 es' 以加在define之前
+	      let change = (shader, shaderType)=>{ 
+	          let newShader = shader
+	          
+	          if(turnTo300){ //非shaderMaterial需要手动改为300 es的写法
+	              addV300 && (newShader = '#version 300 es \n' + newShader)   //需要加 #version 300 es。 three.js自带的渲染会自动加所以不用
+	              newShader = newShader.replaceAll('varying ', shaderType == 'vs' ? 'out ' : 'in ')
+	              newShader = newShader.replaceAll('attribute ', 'in ') 
+	              if(shaderType == 'fs'){
+	                  newShader = newShader.replaceAll('gl_FragColor', 'fragColor')
+	                  newShader = newShader.replace('void main', 'out vec4 fragColor;\n  void main' )//在void main前加入这个声明 
+	              }  
+	              newShader = newShader.replaceAll('gl_FragDepthEXT','gl_FragDepth')
+	          
+	              newShader = newShader.replaceAll('texture2D','texture')
+	              newShader = newShader.replaceAll('textureCube','texture')
+	          
+	          }
+	          
+	          newShader = newShader.replace('#extension GL_EXT_frag_depth : enable','') 
+	          newShader = newShader.replaceAll('defined(GL_EXT_frag_depth) &&','')
+	           
+	          
+	          otherReplaces.forEach(({oldStr,newStr})=>{
+	              newShader = newShader.replaceAll(oldStr,newStr)   
+	          })
+	              
+	          return newShader
+	      }
+	      
+	      vs = change(vs,'vs')
+	      fs = change(fs,'fs')
+	       
+	      //console.log('成功替换为webgl2' )
+	      return {vs,fs}
+	  }//three.js的shaderMaterial也有替换功能,搜 '#define gl_FragDepthEXT gl_FragDepth',
+	   */
 	  changeShaderToWebgl2(vs, fs, matType) {
 	    var otherReplaces = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : [];
 	    //部分shader要根据webgl版本作更改
@@ -4889,24 +4933,24 @@
 	      if (turnTo300) {
 	        //非shaderMaterial需要手动改为300 es的写法
 	        addV300 && (newShader = '#version 300 es \n' + newShader); //需要加 #version 300 es。 three.js自带的渲染会自动加所以不用
-	        newShader = newShader.replaceAll('varying ', shaderType == 'vs' ? 'out ' : 'in ');
-	        newShader = newShader.replaceAll('attribute ', 'in ');
+	        newShader = this.replaceAll(newShader, 'varying ', shaderType == 'vs' ? 'out ' : 'in ');
+	        newShader = this.replaceAll(newShader, 'attribute ', 'in ');
 	        if (shaderType == 'fs') {
-	          newShader = newShader.replaceAll('gl_FragColor', 'fragColor');
+	          newShader = this.replaceAll(newShader, 'gl_FragColor', 'fragColor');
 	          newShader = newShader.replace('void main', 'out vec4 fragColor;\n  void main'); //在void main前加入这个声明 
 	        }
-	        newShader = newShader.replaceAll('gl_FragDepthEXT', 'gl_FragDepth');
-	        newShader = newShader.replaceAll('texture2D', 'texture');
-	        newShader = newShader.replaceAll('textureCube', 'texture');
+	        newShader = this.replaceAll(newShader, 'gl_FragDepthEXT', 'gl_FragDepth');
+	        newShader = this.replaceAll(newShader, 'texture2D', 'texture');
+	        newShader = this.replaceAll(newShader, 'textureCube', 'texture');
 	      }
 	      newShader = newShader.replace('#extension GL_EXT_frag_depth : enable', '');
-	      newShader = newShader.replaceAll('defined(GL_EXT_frag_depth) &&', '');
+	      newShader = this.replaceAll(newShader, 'defined(GL_EXT_frag_depth) &&', '');
 	      otherReplaces.forEach(_ref2 => {
 	        var {
 	          oldStr,
 	          newStr
 	        } = _ref2;
-	        newShader = newShader.replaceAll(oldStr, newStr);
+	        newShader = this.replaceAll(newShader, oldStr, newStr);
 	      });
 	      return newShader;
 	    };
@@ -19637,8 +19681,8 @@
 	};
 	Utils.datasetRotTransform = function () {
 	  var o = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
-	  var pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e => e.dataset_id == o.datasetId);
-	  if (pointcloud) {
+	  var object = o.pointcloud || viewer.scene.pointclouds.find(e => e.dataset_id == o.datasetId) || o.object || viewer.objs.children.find(e => e.dataset_id == o.datasetId);
+	  if (object) {
 	    var matrix, newMatrix, result;
 	    if (o.rotation) {
 	      matrix = new Matrix4().makeRotationFromEuler(o.rotation);
@@ -19649,7 +19693,13 @@
 	    } else {
 	      return;
 	    }
-	    var rotateMatrix = o.fromDataset ? pointcloud.rotateMatrix : pointcloud.rotateInvMatrix;
+	    var rotateMatrix = o.fromDataset ? object.rotateMatrix : object.rotateInvMatrix;
+	    if (!rotateMatrix) {
+	      rotateMatrix = new Matrix4().makeRotationFromEuler(object.rotation); //如果是没有漫游点的模型,在此临时获取一个,但和有漫游点的比会有所不同,因为没有初始旋转(如转90度)
+	      if (o.toDataset) {
+	        rotateMatrix.invert();
+	      }
+	    }
 	    newMatrix = new Matrix4().multiplyMatrices(rotateMatrix, matrix);
 	    if (o.getRotation) {
 	      result = new Euler().setFromRotationMatrix(newMatrix);
@@ -22614,7 +22664,7 @@
 	  isOfficial: false,
 	  webSite: 'testdata',
 	  //正式:'datav1', //不同环境对应的静态文件的地址不同
-
+	  // language : "zh"
 	  isLocal: false,
 	  //是否本地 局域网版本
 	  libsUrl: '../libs/',
@@ -23388,14 +23438,16 @@
 	    //if(Potree.settings.mapCompany == 'google')return 
 	    if (style == this.style) return;
 	    if (Potree.settings.mapCompany == 'google') {
-	      if (style == 'satellite') {
-	        //卫星
-	        this.baseUrl = "https://mt2.google.com/vt/lyrs=y@159000000&hl=zh-CN&gl=cn&x=${x}&y=${y}&z=${z}&s=mt1"; /* "http://mt2.google.cn/vt/lyrs=m@177000000&hl=zh-CN&gl=cn&src=app&x=${x}&y=${y}&z=${z}"  */ //最高只到19
-	        this.maxDepth = 22;
-	      } else {
-	        this.baseUrl = "https://mt2.google.com/vt/lyrs=m@159000000&hl=zh-CN&gl=cn&x=${x}&y=${y}&z=${z}&s=mt1"; /* "http://mt2.google.cn/vt/lyrs=m@177000000&hl=zh-CN&gl=cn&src=app&x=${x}&y=${y}&z=${z}"  */ //最高只到19
-	        this.maxDepth = 22;
-	      }
+	      var [lang, glPos] = {
+	        'zh': ["zh-CN", "cn"],
+	        'en': ["en-US"],
+	        //范围大所以不指定地理位置 。
+	        'ja': ["ja-JP", "JP"],
+	        'kr': ["ko-KR", "KR"]
+	      }[Potree.settings.language] || [];
+	      this.baseUrl = "https://mt2.google.com/vt/lyrs=" + (style == 'satellite' ? "y" : "m") + "@159000000" + (lang ? "&hl=" + lang : '') + (glPos ? "&gl=" + glPos : '') + "&x=${x}&y=${y}&z=${z}&s=mt1";
+	      this.maxDepth = 22;
+
 	      /* 1)lyrs= 表示的是图层类型,即瓦片类型,具体含义如下: 
 	      m:路线图 
 	      t:地形图 
@@ -23403,9 +23455,12 @@
 	      s:卫星图 
 	      y:带标签的卫星图 
 	      h:标签层(路名、地名等)
-	      2)& gl=CN 
+	      2)& gl=CN    指定地理区域
 	      谷歌地图针对中国有两套坐标,一套做了偏移,一套没有。经测试在url加入gl=cn地图会有偏移。 
-	      Tips:如果谷歌地图和RTK测量的WGS84坐标有偏差,可以尝试在url里去掉& gl=cn。
+	      Tips:如果谷歌地图和RTK测量的WGS84坐标有偏差,可以尝试在url里去掉& gl=cn。(摘自网上)
+	      
+	      通义千问:如果不指定gl参数,Google将使用默认值或基于其他因素(如IP地址)来推断用户的地理区域。这通常不会导致地图数据的不准确性,但可能会影响本地化信息的显示。地图上的标签(如街道名称、城市名称等)可能不会以最合适的语言显示。地址格式和拼写可能不符合当地标准
+	      
 	      5)&hl= 
 	      设置地图注记文字语言类型,缺省默认为中文。 
 	      hl=nl 中英双语 
@@ -27752,7 +27807,7 @@
 	      //2048
 	      this.queueTilesInDirectionForPano(i, tileDownloader, this.priorityCriteria.pano, c, this.priorityCriteria.cameraPosition, this.priorityCriteria.cameraDirs, TilePrioritizer.DIRECTIONAL_FOV_NARROW);
 	    }
-	    if (this.canDownloadSize(h)) {
+	    if (this.canDownloadSize(h) && this.priorityCriteria.pano.pointcloud.tileRes != '2k') {
 	      //4096
 	      this.queueTilesInDirectionForPano(i, tileDownloader, this.priorityCriteria.pano, h, this.priorityCriteria.cameraPosition, this.priorityCriteria.cameraDirs, TilePrioritizer.DIRECTIONAL_FOV_NARROW);
 	    }
@@ -27767,7 +27822,7 @@
 	      //2048
 	      this.queueTilesInDirectionForPano(i, tileDownloader, this.priorityCriteria.pano, c, this.priorityCriteria.cameraPosition, this.priorityCriteria.cameraDirs, TilePrioritizer.DIRECTIONAL_FOV);
 	    }
-	    if (this.canDownloadSize(h)) {
+	    if (this.canDownloadSize(h) && this.priorityCriteria.pano.pointcloud.tileRes != '2k') {
 	      //4096
 	      this.queueTilesInDirectionForPano(i, tileDownloader, this.priorityCriteria.pano, h, this.priorityCriteria.cameraPosition, this.priorityCriteria.cameraDirs, TilePrioritizer.DIRECTIONAL_FOV);
 	    }
@@ -28831,6 +28886,7 @@
 	      tileIndex = o.tileIndex,
 	      sceneCode = o.pano.pointcloud.sceneCode,
 	      useV4url = Potree.settings.useV4url && o.pano.pointcloud.datasetData.sceneVersion == 'V4'; //v4的全景图等路径不一样  
+	    var resolution = o.pano.pointcloud.tileRes || '4k';
 	    var metadata = {
 	      sceneScheme: 10
 	    };
@@ -28851,7 +28907,7 @@
 	    } else {
 	      //阿里云oss的规则   if (metadata.sceneScheme == 10) 
 
-	      d = 'tiles/4k/' + id + '_skybox' + h + '.jpg?x-oss-process=';
+	      d = 'tiles/' + resolution + '/' + id + '_skybox' + h + '.jpg?x-oss-process=';
 	      if (e[panoSize] == '512') {
 	        d += 'image/resize,h_512';
 	      } else {
@@ -28860,7 +28916,7 @@
 	          //https://4dkk.4dage.com/images/imagesx4iqYDG3/tiles/4k/122_skybox0.jpg?x-oss-process=image/resize,m_lfit,w_1024/crop,w_512,h_512,x_511,y_0
 	          d += 'image/resize,m_lfit,w_' + panoSize + '/crop,w_512,h_512,';
 	        } else {
-	          d = 'tiles/4k/' + id + '_skybox' + h + '.jpg?x-oss-process=image/crop,w_512,h_512,';
+	          d = 'tiles/' + resolution + '/' + id + '_skybox' + h + '.jpg?x-oss-process=image/crop,w_512,h_512,';
 	        }
 	        //起始位置
 	        if (t.tileX == 0) {
@@ -29263,7 +29319,7 @@
 	  }
 	  queueTileUpload(e, t, i) {
 	    var n = this.getActiveRenderTargetDescriptor(e.panoId);
-	    if (this.isRenderTargetDescriptorValid(n) && e.downloaded && !this.isTileUploaded(e) && (!e.uploadQueued || i) && (!(e.panoSize > this.qualityManager.getMaxNavPanoSize()) || this.zoomingActive)) {
+	    if (this.isRenderTargetDescriptorValid(n) && e.downloaded && !this.isTileUploaded(e) && (!e.uploadQueued || i) && (!(e.panoSize > this.qualityManager.getMaxNavPanoSize()) || this.zoomingActive && viewer.images360.getPano(e.panoId).tileRes != '2k')) {
 	      var r = this.getUploadQueueForPano(e.panoId);
 	      //console.log(window.sceneName, 'queueTileUpload: ', e.panoId, e.tileIndex,   i)
 	      if (i) {
@@ -30320,20 +30376,7 @@
 	        this.cube.material.defines.depth_background = ''; //skybox的深度改得向后一些, 避免盖住chunk,造成坑坑洼洼
 
 	        this.addEventListener('endChangeMode', e => {
-	          var _this$currentPano;
-	          if ((_this$currentPano = this.currentPano) !== null && _this$currentPano !== void 0 && (_this$currentPano = _this$currentPano.pointcloud) !== null && _this$currentPano !== void 0 && _this$currentPano.is4dkkModel) {
-	            var model = this.currentPano.pointcloud;
-	            if (model.fileType == '3dTiles') {
-	              viewer.setAllTilesets(model, child => {
-	                child.runtime.limit2lowestDepth(e.mode == 'showPanos');
-	                child.runtime.getTileset().tiles.forEach(e => {
-	                  this.judgeModelMat(e.tileContent);
-	                });
-	              });
-	            } else {
-	              this.judgeModelMat(model);
-	            }
-	          }
+	          viewer.objs.children.forEach(e => this.changeModelMat(e)); //干脆全部换,就不容易错
 	        });
 	      }
 	    }
@@ -30754,13 +30797,28 @@
 	      }
 	    });
 	  }
-	  judgeModelMat(object) {
+	  changeModelMat(model /* , isCurModel */) {
+	    if (model !== null && model !== void 0 && model.is4dkkModel) {
+	      if (model.fileType == '3dTiles') {
+	        viewer.setAllTilesets(model, child => {
+	          child.runtime.limit2lowestDepth(Potree.settings.displayMode == 'showPanos');
+	          child.runtime.getTileset().tiles.forEach(e => {
+	            this.judgeModelMat(e.tileContent /* , isCurModel */);
+	          });
+	        });
+	      } else {
+	        this.judgeModelMat(model /* , isCurModel */);
+	      }
+	    }
+	  }
+	  judgeModelMat(object /* , isCurModel */) {
 	    if (!(Potree.settings.mergeType2 && Potree.settings.modelSkybox)) return;
 	    object.traverse(mesh => {
 	      if (mesh.material) {
 	        if (!mesh.materialOutside) {
 	          mesh.materialOutside = mesh.material;
 	        }
+	        //mesh.material = Potree.settings.displayMode == 'showPanos' && (this.nextPano?.pointcloud == object || this.currentPano.pointcloud == object || isCurModel) ? this.materialInside : mesh.materialOutside 
 	        mesh.material = Potree.settings.displayMode == 'showPanos' ? this.materialInside : mesh.materialOutside;
 	        Potree.Utils.setObjectLayers(mesh, Potree.settings.displayMode == 'showPanos' ? 'skybox' : 'model'); //为了渲染到rtEDL
 	      }
@@ -31436,23 +31494,25 @@
 
 	    var getNeighbour = (mainPano, subPano) => {
 	      var dirPoints = [[subPano.position, mainPano.position]]; //注: 点A能到B不代表点B能到A,因为拍摄时物体会移动,或点位相对位置不对,无论是否是意外遮挡都且记下来,反正最后只要有一方可行就算相邻。
+	      if (new Vector2().subVectors(subPano.position, mainPano.position).length() > 1e-4) {
+	        //xy都不同
 
-	      if (dis < 20) {
-	        //在远处去掉对floorPosition的判断
-	        dirPoints.push([subPano.floorPosition.clone().add(new Vector3(0, 0, 0.1)), mainPano.position]);
-	      }
-	      if (dis < 12) {
-	        //为了防止楼梯拐角、杂点遮挡。 尽量只在穿墙时不可通行
-	        dirPoints.push([subPano.position.clone().add(new Vector3(0, 0, 0.8)), mainPano.position]);
-	        var normal = math.getNormal2d({
-	          p1: subPano.position,
-	          p2: mainPano.position
-	        }).multiplyScalar(0.3); //左右方向
+	        if (dis < 20) {
+	          //在远处去掉对floorPosition的判断
+	          dirPoints.push([subPano.floorPosition.clone().add(new Vector3(0, 0, 0.1)), mainPano.position]);
+	        }
+	        if (dis < 12) {
+	          //为了防止楼梯拐角、杂点遮挡。 尽量只在穿墙时不可通行
+	          dirPoints.push([subPano.position.clone().add(new Vector3(0, 0, 0.8)), mainPano.position]);
+	          var normal = math.getNormal2d({
+	            p1: subPano.position,
+	            p2: mainPano.position
+	          }).multiplyScalar(0.3); //左右方向
 
-	        dirPoints.push([subPano.position.clone().add(new Vector3(normal.x, normal.y, 0.1)), mainPano.position]);
-	        dirPoints.push([subPano.position.clone().add(new Vector3(-normal.x, -normal.y, 0.1)), mainPano.position]);
+	          dirPoints.push([subPano.position.clone().add(new Vector3(normal.x, normal.y, 0.1)), mainPano.position]);
+	          dirPoints.push([subPano.position.clone().add(new Vector3(-normal.x, -normal.y, 0.1)), mainPano.position]);
+	        }
 	      }
-
 	      //console.warn('getNeighbour', mainPano.id,subPano.id)
 	      for (var i = 0; i < dirPoints.length; i++) {
 	        var dir = new Vector3().subVectors(dirPoints[i][0], dirPoints[i][1]).normalize();
@@ -32091,6 +32151,10 @@
 	          this.panoRenderer.renderPanoTiles(pano.id, null, !1, !1);
 	          pano.setZoomed(ifZoom);
 	        };
+	        if (currentPano.pointcloud.tileRes == '2k') {
+	          //融合页面
+	          return currentPano.zoomed && o(currentPano, !1);
+	        }
 	        if (r && (!currentPano.zoomed || this.qualityManager.zoomLevelResolution && this.qualityManager.zoomLevelResolution != '4k')) {
 	          //needZoom
 	          currentPano.zoomed || o(currentPano, !0);
@@ -34996,7 +35060,8 @@
 	    var easeName = arguments.length > 4 ? arguments[4] : undefined;
 	    var callback = arguments.length > 5 ? arguments[5] : undefined;
 	    //前两个参数有xy即可
-	    endPosition = new Vector3(endPosition.x, endPosition.y, Potree.config.map.cameraHeight);
+	    var z = Math.max(Potree.config.map.cameraHeight, endPosition.z + (boundSize !== null && boundSize !== void 0 && boundSize.z ? boundSize.z / 2 : 0));
+	    endPosition = new Vector3(endPosition.x, endPosition.y, z);
 	    this.view.moveOrthoCamera(this.viewports[0], {
 	      endPosition,
 	      boundSize,
@@ -36139,6 +36204,7 @@
 	        //2022-12-21又换回非固定值。因为有的场景如SS-t-t01myDqnfE的两个数据集密集程度差别很大,应该将稀疏点云的大小设置的大些。 但是这样的缺点是两个数据集因相接处有大有小无法融合。
 	        size = _base * 20 * num_;
 	      }
+	      //不同数据集点云最高级别时的间距不同,但不知道如何计算,  级别越高点云越密,spacing越大初始级别越密。 但实际并非2的level次方,底数可能1-2之间
 	    }
 	    //console.log('changePointSize:'  + this.dataset_id + ' , num: ' + (num && num.toPrecision(3)) + ' , size: ' + size.toPrecision(3),  'nodeMaxLevel', nodeMaxLevel.toPrecision(3), 'testMaxNodeCount',this.testMaxNodeCount     /* this.material.spacing */)
 	    if (size) {
@@ -75193,7 +75259,7 @@
 	    domElement = document;
 	  }
 	  Object3D.call(this);
-	  this.visible = false;
+	  Potree.Utils.updateVisible(this, 'attach', false);
 	  this.domElement = domElement;
 	  var _gizmo = new TransformControlsGizmo(options);
 	  this.add(_gizmo);
@@ -75337,11 +75403,12 @@
 	  };
 
 	  // Set current object
-	  this.attach = function (object) {
+	  this.attach = function (object, clickPos) {
 	    this.object = object;
-	    this.visible = true;
+	    Potree.Utils.updateVisible(this, 'attach', true);
 	    //Config.keyCon = false;//add
 	    //this.linesAssistance.setVisible(true)
+	    this.clickPos = clickPos !== null && clickPos !== void 0 && clickPos.isVector3 ? clickPos : null;
 	    viewer.dispatchEvent('content_changed');
 	    return this;
 	  };
@@ -75349,10 +75416,9 @@
 	  // Detatch from object
 	  this.detach = function () {
 	    this.object = undefined;
-	    this.visible = false;
 	    this.axis = null;
 	    //Config.keyCon = true;//add
-
+	    Potree.Utils.updateVisible(this, 'attach', false);
 	    //this.linesAssistance.setVisible(false)
 	    viewer.dispatchEvent('content_changed');
 	    return this;
@@ -75403,9 +75469,11 @@
 	      this.object.updateMatrixWorld();
 	      this.object.parent.matrixWorld.decompose(parentPosition, parentQuaternion, parentScale);
 	      this.object.matrixWorld.decompose(worldPosition, worldQuaternion, worldScale);
-
-	      //add
-	      if (this.object.boundingBox) {
+	      if (Potree.settings.mergeTransCtlOnClick && this.mode == 'translate' && this.clickPos) {
+	        //允许位移控件出现在点击的位置
+	        var pos = this.clickPos.clone().applyMatrix4(this.object.matrixWorld);
+	        worldPosition.copy(pos);
+	      } else if (this.object.boundingBox) {
 	        var boundingBox = this.object.boundingBox.clone().applyMatrix4(this.object.matrixWorld);
 	        boundingBox.getCenter(worldPosition); //bound中心
 	        if (this.pivotOnBottom) {
@@ -76732,11 +76800,20 @@
 	      if (e.intersect) {
 	        var object = e.intersect.object || e.intersect.pointcloud;
 	        var objects = this.getAllObjects();
+	        var posInModel = Potree.Utils.datasetPosTransform({
+	          toDataset: true,
+	          position: e.intersect.location.clone(),
+	          object
+	        });
 	        if (objects.includes(object) && this.selected != object) {
-	          this.selectModel(object);
+	          this.selectModel(object, posInModel);
 	        } else {
 	          //if(!viewer.inputHandler.selection[0]){//正在平移和旋转,不允许取消
-	          this.selectModel(null);
+	          if (this.selected == object && this.transformControls.mode == 'translate') {
+	            this.selectModel(object, posInModel); //update click pos
+	          } else {
+	            this.selectModel(null);
+	          }
 	          //}
 	        }
 	      } else {
@@ -76985,6 +77062,13 @@
 	      model = this.selected;
 	      state = false;
 	    }
+	    if (!by2d && model) {
+	      model.dispatchEvent({
+	        type: 'changeSelect',
+	        selected: state,
+	        clickPos: state
+	      });
+	    }
 	    if (state) {
 	      if (this.selected) {
 	        if (this.selected == model) return;else {
@@ -77008,12 +77092,6 @@
 	      this.transformControls.detach(); //viewer.transformObject(null);
 	      //console.log('selectModel', null)
 	    }
-	    if (!by2d && model) {
-	      model.dispatchEvent({
-	        type: 'changeSelect',
-	        selected: state
-	      });
-	    }
 	  },
 	  updateBoxHelper(model) {
 	    var size = new Vector3();
@@ -77028,7 +77106,7 @@
 	    this.boxHelper.quaternion.copy(model.quaternion);
 	  },
 	  showModelOutline(model, state) {
-	    if (Potree.settings.mergeType2 || model ? model.fileType == '3dgs' : this.boxHelper.visible) {
+	    if (Potree.settings.mergeType2 || (model ? model.fileType == '3dgs' : this.boxHelper.visible)) {
 	      //高斯很卡
 	      if (state !== false) {
 	        this.updateBoxHelper(model);
@@ -77186,7 +77264,6 @@
 	    //反向求transformMatrix  参考Alignment.js   移动漫游点 
 	    if (model.isPointcloud && model.transformMatrix) {
 	      model.transformMatrix.multiplyMatrices(model.matrix, model.pos1MatrixInvert);
-	      model.transformInvMatrix.copy(model.transformMatrix).invert();
 	      model.rotateMatrix = new Matrix4().makeRotationFromEuler(model.rotation);
 	      model.panos.forEach(e => e.transformByPointcloud());
 	    } else if (model.panos) {
@@ -77195,6 +77272,10 @@
 	      model.panos.forEach(e => e.transformByPointcloud());
 	      model.bound = model.boundingBox.clone().applyMatrix4(model.matrixWorld);
 	    }
+	    if (model.panos) {
+	      model.transformInvMatrix.copy(model.transformMatrix).invert();
+	      model.rotateInvMatrix.copy(model.rotateMatrix).invert();
+	    }
 	    model.lastMatrixWorld = model.matrixWorld.clone();
 	    viewer.dispatchEvent('content_changed');
 	    viewer.mapViewer && Potree.settings.showObjectsOnMap && viewer.mapViewer.dispatchEvent('content_changed');
@@ -77345,8 +77426,10 @@
 
 	要注意getHoveredElements只在getIntersect时才使interactables包含加载的model, 也就是model上不能有使之成为interactables的事件,否则在鼠标hover到模型上开始转动的一瞬间很卡。
 
-
-
+	控制台断开完全重合的漫游点的方法
+	window.pano1 = viewer.modules.PanoEditor.selectedPano //选中第一个点后输入这行,得到第一个漫游点
+	window.pano2 = viewer.modules.PanoEditor.selectedPano //选中第二个点后输入这行,得到第二个漫游点
+	viewer.modules.PanoEditor.linkChange(window.pano1, window.pano2, 'remove') //断开链接
 
 
 	*/
@@ -79792,6 +79875,182 @@
 	  removeAnimation(animation) {
 	    animation.dispatchEvent('dispose');
 	    viewer.scene.removeCameraAnimation(animation);
+	  },
+	  createMulAnimation(data) {
+	    //新版,包含漫游点
+	    var event_ = new EventDispatcher();
+	    var sections = []; //分段, 分成animation和漫游点
+	    var aniIndex = 0;
+	    var curAni,
+	      addAnimation = () => {
+	        if (curAni) {
+	          var data_ = {
+	            name: 'animation_' + aniIndex,
+	            duration: curAni.slice(0, curAni.length - 1).reduce(function (total, currentValue) {
+	              return total + currentValue.time;
+	            }, 0),
+	            //总时长(要去掉最后一个,因为已到终点,该点time无意义)
+	            useDurSlice: data.useDurSlice,
+	            points: curAni
+	          };
+	          var ani = this.createAnimation(data_);
+	          sections.push(ani);
+	          ani.originIndexStart = data.points.indexOf(curAni[0]);
+	          ani.addEventListener('updateCurrentIndex', e => {
+	            emitIndex(e.currentIndex);
+	          });
+	          curAni = null;
+	        }
+	      };
+	    data.points.forEach((e, i) => {
+	      //切分为若干个animation,中间是漫游点的衔接
+	      if (e.panoId != void 0) {
+	        //暂定:有panoId的都是全景图模式
+	        var pano = e.model.panos.find(a => a.originID == e.panoId);
+	        if (pano) {
+	          addAnimation(); //如果前面是动画,先截断  
+	          e.pano = pano;
+	          e.rotInModel = new Quaternion().fromArray(e.rotInModel);
+	          e.quaternion = Potree.Utils.datasetRotTransform({
+	            fromDataset: true,
+	            quaternion: e.rotInModel,
+	            getQuaternion: true,
+	            object: e.model
+	          });
+	          sections.push(e);
+	        }
+	      } else {
+	        if (curAni) {
+	          curAni.push(e);
+	        } else {
+	          //非pano
+	          if (sections.length > 0) {
+	            var last = sections[sections.length - 1]; //因为要从上一个pano出来,所以起始点是上一个pano
+	            last.position = last.pano.position;
+	            last.target = last.position.clone().add(new Vector3(0, 0, -1).applyQuaternion(last.quaternion));
+	            curAni = [last, e];
+	          } else {
+	            curAni = [e];
+	          }
+	        }
+	      }
+	    });
+	    addAnimation();
+	    var currentPlay;
+	    var emitIndex = function emitIndex() {
+	      var indexInAni = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0;
+	      var ani = sections[currentPlay];
+	      var currentIndex = 0;
+	      if (ani instanceof CameraAnimation$1) {
+	        currentIndex = ani.originIndexStart + indexInAni;
+	      } else {
+	        currentIndex = Math.max(0, data.points.indexOf(ani) - 1);
+	      }
+	      event_.dispatchEvent({
+	        type: 'updateCurrentIndex',
+	        currentIndex
+	      });
+	    };
+	    var result = {
+	      event_,
+	      play() {
+	        //从头播放 
+
+	        var playNext = index => {
+	          if (index == sections.length) {
+	            return event_.dispatchEvent('playDone');
+	          }
+	          var ani = sections[index];
+	          currentPlay = index;
+	          emitIndex();
+	          if (ani instanceof CameraAnimation$1) {
+	            Potree.settings.displayMode = 'showPointCloud';
+	            ani.addEventListener('playDone', () => {
+	              playNext(index + 1);
+	            }, {
+	              once: true
+	            });
+	            ani.play();
+	          } else {
+	            var pano = ani.pano;
+	            var last = sections[index - 1],
+	              duration,
+	              quaternion = ani.quaternion;
+	            if (last) {
+	              if (last instanceof CameraAnimation$1) {
+	                duration = last.durations[last.durations.length - 1]; //最后一个时间
+	              } else {
+	                duration = last.time;
+	              }
+	              duration *= 1000;
+	            } else {
+	              duration = 600; //起始
+	            }
+	            viewer.images360.flyToPano({
+	              pano,
+	              quaternion,
+	              duration,
+	              callback: () => {
+	                var next = () => {
+	                  var stayTime = (!sections[index - 1] || sections[index - 1] instanceof CameraAnimation$1) && sections[index + 1] && sections[index + 1] instanceof CameraAnimation$1 ? 1000 : 300; //前后都是点云模式的话停留久一点。最好在页面上能设置
+	                  console.log('stayTime', stayTime);
+	                  setTimeout(() => {
+	                    currentPlay != void 0 && playNext(index + 1);
+	                  }, stayTime); //稍作停留,不然点云-全景-点云的话根本看不到全景
+	                };
+	                if ( /* ani.displayMode == 'showPanos' &&  */Potree.settings.displayMode != 'showPanos') {
+	                  //刚加载完就飞走吗?
+	                  Potree.settings.displayMode = 'showPanos';
+	                  viewer.images360.addEventListener('endChangeMode', () => {
+	                    next();
+	                  }, {
+	                    once: true
+	                  });
+	                } else {
+	                  next();
+	                }
+	                //
+	              }
+	            });
+	          }
+	        };
+	        playNext(0);
+	      },
+	      stop() {
+	        var ani = sections[currentPlay];
+	        if (ani instanceof CameraAnimation$1) {
+	          ani.pause();
+	        } else {
+	          var view = viewer.mainViewport.view;
+	          if (!view.isFlying('pos')) {
+	            //前后是相同漫游点,仅旋转
+	            view.cancelFlying('rotate');
+	          } else {
+	            //加快结束
+	            var o = transitions.getById(view.FlyTransition)[0];
+	            var restDur = o.duration - o.current;
+	            var hopeStopTime = 300; //希望最多等待时间
+	            if (restDur > hopeStopTime) {
+	              var r = o.duration / (o.current + hopeStopTime);
+	              transitions.adjustSpeed(view.FlyTransition, r);
+	              transitions.adjustSpeed(view.LookTransition, r);
+	            }
+	          }
+	          //如果有地图,还要改地图的view
+	        }
+	        currentPlay = null;
+	      },
+	      remove() {
+	        sections.forEach(ani => {
+	          if (ani instanceof CameraAnimation$1) {
+	            CamAniEditor.removeAnimation(ani);
+	          }
+	        });
+	      }
+
+	      //再把中间的缓动去除
+	    };
+	    return result;
 	  }
 	};
 
@@ -89821,7 +90080,12 @@
 	      }); //更新viewports相机透视 使focusOnObject在此窗口大小下
 
 	      prisms.forEach(prism => {
-	        points.push(...prism.points);
+	        var prismPoints = prism.points.slice();
+	        if (prism.baseModel) {
+	          var currentBound = prism.baseModel.currentBound || prism.baseModel.boundingBox.clone().applyMatrix4(prism.baseModel.matrixWorld);
+	          prismPoints = prismPoints.map(e => e.clone().setZ(Math.max(e.z, currentBound.max.z)));
+	        }
+	        points.push(...prismPoints);
 	        prism.setSelected(false);
 	        prism.changeStyleForScreenshot(true, {
 	          hideLabel: info.type != 'prism2d-all',
@@ -90007,10 +90271,12 @@
 	        }
 	        if (o.focusBoundCenter) {
 	          boundOri.getCenter(target);
+	          target.z += 1;
 	        }
 	        var boundSizeOri = boundOri.getSize(new Vector3());
-	        var boundSizeMap = boundSizeOri.clone().multiplyScalar(o.boundExpandRatio || math.linearClamp(Math.max(boundSizeOri.x, boundSizeOri.y), [0.5, 30], [2.5, 1.2])); //为了能同时看清测量线和地图,当测量线较短时,扩大margin,防止地图过度放大
-
+	        var expand = o.boundExpandRatio || math.linearClamp(Math.max(boundSizeOri.x, boundSizeOri.y), [0.5, 30], [2.5, 1.2]); //为了能同时看清测量线和地图,当测量线较短时,扩大margin,防止地图过度放大
+	        var boundSizeMap = boundSizeOri.clone();
+	        boundSizeMap.x *= expand, boundSizeMap.y *= expand;
 	        boundSizeMap.x = Math.max(minBound.x, boundSizeMap.x);
 	        boundSizeMap.y = Math.max(minBound.y, boundSizeMap.y);
 	        this.mapViewer.moveTo(target.clone(), boundSizeMap, duration, o.margin, null, done);
@@ -92520,7 +92786,7 @@
 	  }
 	  return loadFile(path, null, callback);
 	}
-	function load4dkkPanos(sceneCode, model, done) {
+	function load4dkkPanos(sceneCode, model, done, tileRes) {
 	  //加载四维看看的漫游点并转换
 	  model.is4dkkModel = true;
 	  model.panos = [];
@@ -92537,9 +92803,12 @@
 	  model.rot1MatrixInvert = rot1M.clone().invert();
 	  model.transformMatrix = new THREE.Matrix4();
 	  model.rotateMatrix = new THREE.Matrix4();
+	  model.transformInvMatrix = new THREE.Matrix4();
+	  model.rotateInvMatrix = new THREE.Matrix4();
 	  model.datasetData = {
 	    sceneVersion: 'V4'
 	  };
+	  model.tileRes = tileRes;
 	  model.sceneCode = sceneCode;
 	  model.bound = new THREE.Box3();
 	  var path = "https://4dkk.4dage.com/scene_view_data/".concat(sceneCode, "/images/vision.txt");

Разлика између датотеке није приказан због своје велике величине
+ 1 - 1
public/static/lib/potree/potree.js.map