xzw 3 years ago
parent
commit
9182cfe7d8

+ 48 - 24
libs/three.js/lines/LineMaterial.js

@@ -246,9 +246,15 @@ ShaderLib[ 'line' ] = {
 			#ifdef USE_DASH
 
 				if ( vUv.y < - 1.0 || vUv.y > 1.0 ) discard; // discard endcaps
-
-				if ( mod( vLineDistance + dashOffset, dashSize + gapSize ) > dashSize ) discard; // todo - FIX
-
+                
+                
+                bool unvisible = mod( vLineDistance + dashOffset, dashSize + gapSize ) > dashSize;
+                //加
+                #ifdef DASH_with_depth
+                    
+                #else  
+                    if (unvisible) discard; // todo - FIX
+                #endif
 			#endif
 
 			if ( abs( vUv.y ) > 1.0 ) {
@@ -261,58 +267,54 @@ ShaderLib[ 'line' ] = {
 
 			}
 
-
+            vec4 diffuseColor = vec4( diffuse, opacity );
             //加
             #if defined(GL_EXT_frag_depth) && defined(useDepth)    
-                // mixFactor and clipFactor define the color mixing proportion between the states of
-                // full visibility and occluded visibility
-                // and
-                // full visibility and total invisibility
+               
                 float mixFactor = 0.0;
                 float clipFactor = 0.0;
 
-                // The linear depth value of the current fragment
                 float fragDepth = convertToLinear(gl_FragCoord.z);
 
-                // The coordinates of the current fragment in the depth texture
                 vec2 depthTxtCoords = vec2(gl_FragCoord.x - viewportOffset.x,  gl_FragCoord.y) / resolution;
 
-                // The linear depth value of the pixel occupied by this fragment in the depth buffer
                 float textureDepth = convertToLinear(texture2D(depthTexture, depthTxtCoords).r);
 
-                // The difference between the two depths
                 float delta = textureDepth - fragDepth;
 
                 if (delta < 0.0)
                 {
-                    // occlusionDistance and clipDistance define the width of the respective zones and
-                    // mixFactor and clipFactor express the interpolation between the two colors depending on the position
-                    // of the current fragment withing those zones.
-                    
                     float occlusionDistance = - 1.0;
                     float clipDistance = - 4.0;
                     mixFactor = clamp(delta / occlusionDistance, 0.0, 1.0);
                     clipFactor = clamp(delta / clipDistance, 0.0, 1.0);
                 }
-                // If the fragment is totally transparent, don't bother drawing it
+                 
                 if (clipFactor == 1.0)
                 {
                     discard;
                 }
                 
-                vec3 backColor = vec3(0.8,0.8,0.8);
+                vec4 backColor = vec4(0.8,0.8,0.8, 0.8*opacity);
                  
+                #ifdef DASH_with_depth  
+                    // 只在被遮住的部分显示虚线
+                    if(unvisible) backColor.a = 0.0;
+                #endif 
                 
-                // Mix between the solid and the dahsed versions of the line according to the mixFactor
-                vec4 diffuseColor = vec4(mix(diffuse, backColor, mixFactor), opacity*(1.0 - clipFactor));
+                //vec4 diffuseColor = vec4(mix(diffuse, backColor, mixFactor), opacity*(1.0 - clipFactor));
+               
+               
+               
+                diffuseColor = mix(diffuseColor, backColor , mixFactor);   
                
-            #else
-                vec4 diffuseColor = vec4( diffuse, opacity );
+               
+                diffuseColor.a *= (1.0 - clipFactor);  
+                
             #endif
  
 
-
-			//vec4 diffuseColor = vec4( diffuse, opacity );
+ 
 
 			#include <logdepthbuf_fragment>
 			#include <color_fragment>
@@ -390,6 +392,28 @@ var LineMaterial = function ( parameters ) {
 			}  
         },
         
+        dashWithDepth:{//add 
+            enumerable: true,
+
+			get: function () {
+
+				return 'DASH_with_depth' in this.defines 
+
+			},
+
+			set: function ( value ) {
+                if(value != this.dashWithDepth){ 
+                    if(value){
+                        this.defines.DASH_with_depth = '' 
+                    }else{
+                        delete this.defines.DASH_with_depth
+                    }
+                    this.needsUpdate = true
+                }
+			}  
+        },
+       
+        
         
 		color: {
 

+ 78 - 46
note.txt

@@ -1,79 +1,65 @@
-https://potree.org/potree/examples/page.html
-
+https://potree.org/potree/examples/page.html 
 http://localhost:1234/examples/page.html
 
-npm start
+ 
 
 应用navvis : 
- https://testlaser.4dkankan.com/maxkk/t-iksBApb/?image=1&vlon=4.91&vlat=-0.13&fov=100.0
+https://testlaser.4dkankan.com/maxkk/t-iksBApb/?image=1&vlon=4.91&vlat=-0.13&fov=100.0
 https://hq.iv.navvis.com/?site=1493761991057195&vlon=1.12&vlat=-0.52&fov=100.0&image=16902
 http://139.224.42.18:8080/siemens/?pc=true&vlon=2.59&vlat=-0.03&fov=100.0&lon=116.46694741&lat=39.98387332&z=1.807
-
-navvis:
 http://indoor.popsmart.cn:8084/sxswsw-sx/?vlon=5.25&vlat=0.03&fov=100.0&pc=true&lon=120.58634810&lat=29.99135414&z=2.002
 
 用户名:admin
 密码:ipadmin
 
-
-
-
-重算 http://120.25.146.52:9294/indoor/{sceneCode}/api/initRecount
-
-
-
-地图贴图
-https://hq.iv.navvis.com/?fov=100.0&site=1493761991057195&hsCtaTracking=8ca25304-e9e7-49a2-8543-fcd4d6cb6df2%7C1108fea0-c576-4606-adbd-64471b0f92a6&vlon=5.90&vlat=-0.30&image=16830
-
-
+ 
 ========
-场景:
-
-t-ia44BhY 机场(两个数据集。点量大 )
-t-iksBApb 一楼 一个数据集 十个点左右
-t-Zvd3w0m 室内 4dkk的场景 三个点 
-t-OW5ShsQ 一楼 有平面图 点五个
-
 
 
 测试服务器可以:
 t-CwfhfqJ 大佛 有平面图 (贴图和点云有微微错位) 
 t-e2Kb2iU 隧道 
 t-8KbK1JjubE  回家湘
-------------
-本地测试
-t-bnC8jkv
-t-20211031
-=============================
-地图lib:ol  全局变量    viewer.mapView
+t-Y22JxCS7sP 小区
+t-8BCqxQAr93 会议室
+t-AY03FoVZhm 一楼 
+t-GusppsiKEC 字节跳动楼外场景
 
 
+ 
+4dkk.html 场景:
 
-PointCloudOctreeGeometryNode-geometry 
+t-ia44BhY 机场(两个数据集。点量大 )
+t-iksBApb 一楼 一个数据集 十个点左右
+t-Zvd3w0m 室内 4dkk的场景 三个点 
+t-OW5ShsQ 一楼 有平面图 点五个
 
+ 
+ 
 
-==============
 
- 
+============== 
 添加数据集登录4dkk
 18666146601
 Aa123456
 
-===============
-
+==========================================================================================
 
 待完善:
 
+
+
+
 ---------
 优化:  |
 ---------
-加载深度图(因为一开始用的全景)
+加载深度图(因为一开始用的全景)( 用深度图来模拟全景漫游的mesh似乎行不通,因为是非线性的,但可以加载chunks,超低模,或者重写点云shader,改成mesh的,只加载到level3)
 setView 旋转改成4dkk那种
 
+当距离很远的过渡可以考虑瞬间过渡
 热点可能需要再次矫正
-飞向object的bound和距离
-四屏透明度不好调整
-
+ 
+ 
 
 
 
@@ -81,8 +67,15 @@ setView 旋转改成4dkk那种
 Bug	|
 ---------
 
-qq浏览器灰白:见pointcloud.vs:暂时注释掉   applyBackfaceCulling直接返回false或者注释color = vec3(0.);都没问题
 
+
+不是我的bug:
+
+有的点位贴图不准,回复说是计算问题。
+
+----------------
+
+ 
 隐藏数据集后再全景
 截图时map为何闪一下
  
@@ -103,16 +96,55 @@ dataset校准导致导航问题、控制点?
 这里要显示的是自定义的平面图,但是如果没有自定义的,应该是不显示这个选项的
 
 
+最高level
+ 
+
+ 海拔颜色阈值调整  第二种模式
+
+
+路径规划AB调换不发请求
+
+地图坐标矫正
+
+高德地图后缀中的lonlat是什么标准?用场景里的输入后显示的位置和场景的地图不一致
+
+
+地图上画的datasetpoints为空
+
+
+
+点云大小怎样才能近似mesh无缝
+ 
+
+测量线点有时出来的很慢
+截图的等待全景图加载的地方写全  现在暂时用的延时
+ 
+
+测量在地图上的高度确定:
+  navvis很奇怪,在地面上很准,但是到了房屋上就只能在当前高度了。在房屋内是依靠空间模型判断属于哪个Floor楼层,得到层高。
+ 
+
+导航在地图上的高度怎么定
+ 
 
 
+http://localhost:8080/epc.html?m=t-CwfhfqJ 漫游点没掉了    平面图无数据
+http://localhost:8080/api/laser/filter/t-CwfhfqJ/query
 
 
-漫游模式的点云有问题。  
+ 
+测试下控制点保存
+
+
+23212 (导航)在导航页面停留一段时间不操作,界面会异常向上转 http://192.168.0.21/index.php?m=bug&f=view&bugID=23212
+ 
+分享的测量线地图上的端点大小有时大有时小
+ 
+
+如果两个人同时打开场景,其中一个保存了地理注册,另一个还在导航,那么得到的都是没有数据 。。。
 
-1 为何切换到用贴图作为点云颜色后点变小 getPointSize-> getLOD(即使把shader中用贴图的去掉,去掉defines.push("#define usePanoMap");, 仅shader.setUniform1i('pano0Map')
-2 为何设置背景色会导致 贴图作为点云颜色时 点云大小闪烁不定(和上面一样,如果不传递图片就没问题)
-3 float getLOD(){ 中的  但是为何只在贴图后才有问题
 
---结果: 是传递图片时写错了
+ 
+
 
- 
+为什么newLocation和我得到的不一样

+ 84 - 7
src/PointCloudOctree.js

@@ -19,9 +19,7 @@ export class PointCloudOctreeNode extends PointCloudTreeNode {
         
         
 	}
-
-    
-
+ 
 	getNumPoints () {
 		return this.geometryNode.numPoints;
 	}
@@ -120,13 +118,14 @@ export class PointCloudOctree extends PointCloudTree {
 		this.level = 0;
 		this.position.copy(geometry.offset);
 		this.updateMatrix();
-        
-        
+        this.nodeMaxLevel = 0;//add
+        this.maxLevel = Infinity;
+        this.temp = {}//add
         //add 
         this.rotateMatrix = new THREE.Matrix4;
         this.transformMatrix = new THREE.Matrix4;// 数据集的变化矩阵
         this.transformInvMatrix = new THREE.Matrix4; 
-        
+        this.material.spacing = this.pcoGeometry.spacing;//初始化一下 以便于设置pointsize
         
 		{
 
@@ -189,8 +188,22 @@ export class PointCloudOctree extends PointCloudTree {
 		this.fallbackProjection = geometry.fallbackProjection;
 
 		this.root = this.pcoGeometry.root;
+        
+        
+        
+        this.pcoGeometry.on('updateNodeMaxLevel', this.updateNodeMaxLevel.bind(this))
+        
 	}
 
+
+    updateNodeMaxLevel(level){//目前点云包含node的最高level
+        var level = Math.max(level, this.nodeMaxLevel)
+        if(level != this.nodeMaxLevel){
+            this.nodeMaxLevel = level 
+            viewer.emit('updateNodeMaxLevel',  this, level) 
+        }
+    }
+
 	setName (name) {
 		if (this.name !== name) {
 			this.name = name;
@@ -327,7 +340,7 @@ export class PointCloudOctree extends PointCloudTree {
 		material.fov = camera.fov * (Math.PI / 180);
 		material.screenWidth = renderer.domElement.clientWidth;
 		material.screenHeight = renderer.domElement.clientHeight;
-		material.spacing = this.pcoGeometry.spacing; // * Math.max(this.scale.x, this.scale.y, this.scale.z);
+		//material.spacing = this.pcoGeometry.spacing; // * Math.max(this.scale.x, this.scale.y, this.scale.z);  //应该不需要
 		material.near = camera.near;
 		material.far = camera.far;
 		material.uniforms.octreeSize.value = this.pcoGeometry.boundingBox.getSize(new THREE.Vector3()).x;
@@ -1157,6 +1170,70 @@ export class PointCloudOctree extends PointCloudTree {
 
 	}
     
+    // 设置点大小
+    changePointSize(num) {
+        if (num == void 0) {
+            num = this.temp.pointSize
+        } else {
+            this.temp.pointSize = num
+        }
+
+        if(Potree.settings.sizeFitToLevel){//按照点云质量来调整的版本:
+            let base = this.material.spacing / Math.pow(2, this.maxLevel) //点云大小在level为0时设置为spacing,每长一级,大小就除以2
+            base *= this.nodeMaxLevel > 0 ? Math.max(0.1, Math.pow(this.maxLevel / this.nodeMaxLevel, 1.3)) : 0.1 //低质量的缩小点,因为视觉上看太大了。navvis是不铺满的,我们也留一点缝隙
+
+            this.material.size = base * 3 * num  
+            //在t-8BCqxQAr93 会议室 和 t-e2Kb2iU 隧道 两个场景里调节,因为它们的spacing相差较大,观察会议室墙壁的龟裂程度
+            
+            
+        }else{
+            let base = this.material.spacing / Math.pow(2, this.nodeMaxLevel) //点云大小在level为0时设置为spacing,每长一级,大小就除以2
+            
+            this.material.size = base * 4 * num 
+        }
+        
+        
+        //console.log('changePointSize ' + this.dataset_id + ', num : ' + num + ' , size : ' + this.material.size, this.material.spacing)
+
+         
+    }  
+    
+    
+    
+    // 设置点透明度
+    changePointOpacity(num) {
+        //num:0-1   navvis用的是亮度
+        if (num == void 0) {
+            num = this.temp.pointOpacity
+        } else {
+            this.temp.pointOpacity = num
+        }
+         
+        if (num == 1) {
+            this.material.opacity = 1
+        } else {
+            if(Potree.settings.sizeFitToLevel){//按照点云质量来调整的版本:
+                let base = this.material.spacing / Math.pow(1.4, this.maxLevel) //随着level提高,点云重叠几率增多
+                let minBase = this.material.spacing / Math.pow(1.4, this.nodeMaxLevel)
+                let ratio = Math.min(1 / base, 1 / minBase / 3) //ratio为一个能使opacity不大于1 的 乘量,minBase要除以一个数,该数调越大减弱效果越强。level越低opacity和面板越接,level越高越效果越弱,以减免过度重叠后的亮度。
+                this.material.opacity = THREE.Math.clamp(base * ratio * num, 0, 0.999) //到1就不透明了(可能出现一段一样)
+            }else{
+                let base = this.material.spacing / Math.pow(1.8, this.maxLevel) 
+                let minBase = this.material.spacing / Math.pow(1.8, this.nodeMaxLevel)
+                //console.log(1 / base, 1 / minBase / 6)
+                let ratio = Math.min(1 / base, 1 / minBase / 9) //ratio为一个能使opacity不大于1 的 乘量,minBase要除以一个数,该数调越大减弱效果越强。level越低opacity和面板越接,level越高越效果越弱,以减免过度重叠后的亮度。
+                this.material.opacity = THREE.Math.clamp(base * ratio * num, 0, 0.999) //到1就不透明了(可能出现一段一样)
+            }
+        
+        }
+        //console.log('changePointOpacity ' + this.dataset_id + ', num : ' + num + ' , opacity : ' + this.material.opacity) //检查是否做到了低质量时num==opacity,中质量opacity稍小于num,高质量更小
+         
+    } 
+    
+    
+    
+    
+    
     
     //数据集的显示影响到其下的:点云、marker  .不会影响地图上的显示
     

+ 8 - 4
src/PointCloudOctreeGeometry.js

@@ -1,13 +1,14 @@
 
-
+import { EventDispatcher } from "./EventDispatcher.js";
 import * as THREE from "../libs/three.js/build/three.module.js";
 import {PointCloudTreeNode} from "./PointCloudTree.js";
 import {XHRFactory} from "./XHRFactory.js";
 import {Utils} from "./utils.js";
 
-export class PointCloudOctreeGeometry{
+export class PointCloudOctreeGeometry extends EventDispatcher{
 
 	constructor(){
+        super()
 		this.url = null;
 		this.octreeDir = null;
 		this.spacing = 0;
@@ -117,7 +118,8 @@ export class PointCloudOctreeGeometryNode extends PointCloudTreeNode{
 		child.parent = this;
 	}
 
-	load(){
+	load(){  
+    
 		if (this.loading === true || this.loaded === true || Potree.numNodesLoading >= Potree.maxNodesLoading) {
 			return;
 		}
@@ -141,7 +143,7 @@ export class PointCloudOctreeGeometryNode extends PointCloudTreeNode{
 		this.pcoGeometry.loader.load(this);
 	}
 
-	loadHierachyThenPoints(){
+	loadHierachyThenPoints(pointcloud){
 		let node = this;
 
 		// load hierarchy
@@ -198,6 +200,8 @@ export class PointCloudOctreeGeometryNode extends PointCloudTreeNode{
 				let parentName = name.substring(0, name.length - 1);
 				let parentNode = nodes[parentName];
 				let level = name.length - 1;
+                pco.emit('updateNodeMaxLevel',level);//add
+                
 				let boundingBox = Utils.createChildAABB(parentNode.boundingBox, index);
 
 				let currentNode = new PointCloudOctreeGeometryNode(name, pco, boundingBox);

+ 4 - 4
src/PotreeRenderer.js

@@ -281,7 +281,7 @@ class Shader {
 			}
 
 			// uniform blocks
-			if(gl instanceof WebGL2RenderingContext){ 
+			if( typeof WebGL2RenderingContext !== 'undefined' && gl instanceof WebGL2RenderingContext){ //WebGL2RenderingContext在mac的safari14以下是没有定义的
 				let numBlocks = gl.getProgramParameter(program, gl.ACTIVE_UNIFORM_BLOCKS);
 
 				for (let i = 0; i < numBlocks; i++) {
@@ -1200,7 +1200,7 @@ export class Renderer {
 		if(params.transparent !== undefined){
 			transparent = params.transparent && material.opacity < 1;
 		}else{
-			transparent = material.opacity < 1;
+			transparent = material.usePanoMap ? false : (material.useFilterByNormal || material.opacity < 1); //add useFilterByNormal
 		}
 
 		if (transparent){
@@ -1308,7 +1308,7 @@ export class Renderer {
 			}
 
 
-			shader.setUniform1f("size", material.usePanoMap ? 0.2 :  material.size);//大概在0.01-0.2之间感觉较好,考虑到有的点云稀疏,用大一点的点
+			shader.setUniform1f("size", material.usePanoMap ? Potree.config.material.absolutePanoramaSize : material.size);//usePanoMap时控制在不大不小的范围内感觉较好,考虑到有的点云稀疏,用大一点的点
 			shader.setUniform1f("maxSize", material.uniforms.maxSize.value);
 			shader.setUniform1f("minSize", material.uniforms.minSize.value);
 
@@ -1321,7 +1321,7 @@ export class Renderer {
 			//uniform vec3 uColor;
 			shader.setUniform3f("uColor", material.color.toArray());
 			//uniform float opacity;
-			shader.setUniform1f("uOpacity", material.opacity);
+			shader.setUniform1f("uOpacity", material.usePanoMap ? 1: material.opacity);
 
 			shader.setUniform2f("elevationRange", material.elevationRange);
 			shader.setUniform2f("intensityRange", material.intensityRange);

+ 2 - 2
src/Potree_update_visibility.js

@@ -303,7 +303,7 @@ export function updateVisibility(pointclouds, camera, areaSize){
 				node = pointcloud.toTreeNode(node, parent);
 				loadedToGPUThisFrame++;
 			} else {
-				unloadedGeometry.push(node);
+				unloadedGeometry.push({pointcloud,node});
 				visibleGeometry.push(node);
 			}
 		}
@@ -405,7 +405,7 @@ export function updateVisibility(pointclouds, camera, areaSize){
 	}
     //加载点云
 	for (let i = 0; i < Math.min(Potree.maxNodesLoading, unloadedGeometry.length); i++) {
-		unloadedGeometry[i].load();
+		unloadedGeometry[i].node.load(unloadedGeometry[i].pointcloud.pcoGeometry); 
 	}
 
 	return {

+ 41 - 17
src/materials/PointCloudMaterial.js

@@ -17,6 +17,10 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {
 	constructor (parameters = {}) {
 		super();
 
+        
+        
+        
+        
 		this.visibleNodesTexture = Utils.generateDataTexture(2048, 1, new THREE.Color(0xffffff));
 		this.visibleNodesTexture.minFilter = THREE.NearestFilter;
 		this.visibleNodesTexture.magFilter = THREE.NearestFilter;
@@ -31,7 +35,7 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {
 
 		let pointSize = getValid(parameters.size, 1.0);
 		let minSize = getValid(parameters.minSize, 2.0);
-		let maxSize = getValid(parameters.maxSize, 50.0);
+		let maxSize = getValid(parameters.maxSize, 1550.0);
 		let treeType = getValid(parameters.treeType, TreeType.OCTREE);
 
 		this._pointSizeType = PointSizeType.FIXED;
@@ -40,7 +44,7 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {
 		this.clipBoxes = [];
 		this.clipPolygons = [];
 		this._weighted = false;
-		this._gradient = Gradients.SPECTRAL;
+		this._gradient = Gradients.RAINBOW//Gradients.SPECTRAL;//海拔贴图种类
 		this.gradientTexture = PointCloudMaterial.generateGradientTexture(this._gradient);
 		this._matcap = "matcap.jpg";
 		this.matcapTexture = Potree.PointCloudMaterial.generateMatcapTexture(this._matcap);
@@ -242,13 +246,13 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {
 		this.vertexShader = vs;
 		this.fragmentShader = fs;
 
-		if (this.opacity === 1.0) {
+		if (this.opacity === 1.0 && !this.useFilterByNormal) {//add useFilterByNormal
 			this.blending = THREE.NoBlending;
 			this.transparent = false;
 			this.depthTest = true;
 			this.depthWrite = true;
 			this.depthFunc = THREE.LessEqualDepth;
-		} else if (this.opacity < 1.0 && !this.useEDL) {
+		} else if (  (this.opacity < 1.0 ||this.useFilterByNormal) &&   !this.useEDL) {//add useFilterByNormal
 			this.blending = THREE.AdditiveBlending;
 			this.transparent = true;
 			this.depthTest = false;
@@ -359,7 +363,7 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {
 		return this._gradient;
 	}
 
-	set gradient (value) {
+	set gradient (value) {//海拔贴图
 		if (this._gradient !== value) {
 			this._gradient = value;
 			this.gradientTexture = PointCloudMaterial.generateGradientTexture(this._gradient);
@@ -656,19 +660,34 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {
 		return this.uniforms.uColor.value;
 	}
 
-	set color (value) {
-		if (!this.uniforms.uColor.value.equals(value)) {
-			this.uniforms.uColor.value.copy(value);
+	set color (value) {//改
+        
+        if(value == this.color_)return
+        let color = value;
+		//if (!this.uniforms.uColor.value.equals(value)) {
+        if(typeof value == 'string') {
+            var colorArr = Potree.config.colors[value]  
+            if(!colorArr){ 
+                console.warn('没找到该颜色值'+ value)
+            }else{
+                color = new THREE.Color().fromArray(colorArr).multiplyScalar(1/255)
+            }                
+            
+        }    
+        this.uniforms.uColor.value.set(color)  
+        //this.uniforms.uColor.value.copy(value);
 			
-			this.dispatchEvent({
-				type: 'color_changed',
-				target: this
-			});
-			this.dispatchEvent({
-				type: 'material_property_changed',
-				target: this
-			});
-		}
+        this.dispatchEvent({
+            type: 'color_changed',
+            target: this
+        });
+        this.dispatchEvent({
+            type: 'material_property_changed',
+            target: this
+        });
+		//}
+        
+        this.color_ = value //记录下str
 	}
 
 	get shape () {
@@ -725,6 +744,9 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {
 		}
 	}
 
+
+     
+
 	get minSize(){
 		return this.uniforms.minSize.value;
 	}
@@ -1171,5 +1193,7 @@ export class PointCloudMaterial extends THREE.RawShaderMaterial {
 	// copy(from){
 	// 	this.copyFrom(from);
 	// }
+    
+    
 
 }

+ 7 - 4
src/materials/shaders/pointcloud.vs

@@ -715,13 +715,16 @@ float getPointSize(){
 	
 	float slope = tan(fov / 2.0);
 	float projFactor = -0.5 * uScreenHeight / (slope * vViewPosition.z);
-
+    /*
 	float scale = length(
 		modelViewMatrix * vec4(0, 0, 0, 1) - 
 		modelViewMatrix * vec4(uOctreeSpacing, 0, 0, 1)
 	) / uOctreeSpacing;
+    
 	projFactor = projFactor * scale;
-	
+	*/
+    
+    
 	float r = uOctreeSpacing * 1.7;
 	//vRadius = r;
      
@@ -733,9 +736,9 @@ float getPointSize(){
 			pointSize = size;
 		}else{  //近大远小,模拟真实mesh,边缘放大
 			//pointSize = size * spacing * projFactor;  //spacing是attribute  为空  如果有这个值就能更自适应填补
-            pointSize = size * uOctreeSpacing * projFactor / 18.0; //直接用cloud的spacing里,不过因为都一样所以可能没有什么意义
+            //pointSize = size * uOctreeSpacing * projFactor / 18.0; //直接用cloud的spacing里,不过因为都一样所以可能没有什么意义
 			//pointSize = pointSize * projFactor;
-           
+            pointSize = size * projFactor  ;
 		}
 	#elif defined adaptive_point_size
 		if(uUseOrthographicCamera) {

+ 111 - 37
src/modules/Images360/Images360.js

@@ -106,6 +106,7 @@ export class Images360 extends EventDispatcher{
 
 
         let scroll = (e)=>{ 
+            if(e.hoverViewport != viewer.mainViewport)return
             let zoom;
             if(Potree.settings.displayMode == 'showPanos' && Potree.settings.zoom.enabled){
                 if(e.delta > 0){
@@ -121,7 +122,7 @@ export class Images360 extends EventDispatcher{
 
 
         viewer.addEventListener('global_click'/* "global_drop" */, (e) => {//不用"mouseup" 是因为 mouseup有drag object时也会触发
-            if(Potree.settings.unableNavigate || this.flying  || e.button != THREE.MOUSE.LEFT  )return //
+            if(Potree.settings.unableNavigate || this.flying  || e.button != THREE.MOUSE.LEFT || e.viewport != viewer.mainViewport )return //
             
             /* if(currentlyHovered && currentlyHovered.pano){
 				this.focusPano(currentlyHovered.pano);
@@ -203,16 +204,25 @@ export class Images360 extends EventDispatcher{
         
         {//切换模式
             let displayMode = '';  
+            let lastRequestMode = '';//因为可能延迟,所以记录下每次的请求模式,延迟后判断这个
             Object.defineProperty(Potree.settings , "displayMode",{  
                 get: function() {
                     return displayMode
                 },
                 set:  (mode)=> {
+                    lastRequestMode = mode                   
                     if(mode != displayMode){
                         let config = Potree.config.displayMode[mode]
                         let config2 
                         let camera = viewer.scene.getActiveCamera()
-                        
+                        if(mode == 'showPanos' && this.flying){//飞完才能切换全景
+                            this.once('cameraMoveDone', ()=>{
+                                if(lastRequestMode == mode){//如果ui还是停在这个模式的话
+                                    Potree.settings.displayMode = mode 
+                                } 
+                            })
+                            return
+                        }
                         if(this.isAtPano() ){//this.currentPano
                             if(this.flying)config2 = config.transition 
                             else config2 = config.atPano 
@@ -220,10 +230,13 @@ export class Images360 extends EventDispatcher{
                             config2 = config.atPano 
                             if(mode == 'showPanos'){//自动飞入一个pano
                                 //要改成飞进最近的。。。 
+                                if(this.panos.length == 0)return
                                 this.flyToPano({
                                     pano: /* this.currentPano ||  */Common.sortByScore(this.panos,null,[e=>-e.position.distanceTo(this.position)])[0].item,   
                                     callback: ()=>{
-                                        Potree.settings.displayMode = mode 
+                                        if(lastRequestMode == mode ){
+                                            Potree.settings.displayMode = mode 
+                                        } 
                                     }
                                 }) 
                                 
@@ -243,9 +256,11 @@ export class Images360 extends EventDispatcher{
                         
                         
                         if(config2.showSkybox || config2.pointUsePanoTex){
-                            if(this.checkAndWaitForPanoLoad(this.currentPano, "low", "low", this.basePanoSize, ()=> {
+                            if(this.checkAndWaitForPanoLoad(this.currentPano,  this.basePanoSize, ()=> {
                                     setTimeout( ()=>{
-                                        Potree.settings.displayMode = mode
+                                        if(lastRequestMode == mode ){
+                                            Potree.settings.displayMode = mode 
+                                        }
                                     },1)
                                 })  
                             ){
@@ -290,15 +305,24 @@ export class Images360 extends EventDispatcher{
                         if(mode == 'showPanos'){  
                             camera.far = viewer.farWhenShowPano  //修改far
                             Potree.settings.pointDensity = 'panorama'
+                            
+                            /*viewer.scene.pointclouds.forEach(e=>{//全景时透明度为1
+                                e.material.opacity = 1  
+                            })*/ //直接在potreeRender里判断了
+                            
+                            
                         }else{
                             if(camera.limitFar)   camera.far = Potree.settings.cameraFar;//修改far
-                            Potree.settings.pointDensity = Potree.settings.UserPointDensity    
+                            Potree.settings.pointDensity = Potree.settings.UserPointDensity   
+
+                            //Potree.sdk && Potree.sdk.scene.changePointOpacity() 
+                            
                         }  
                         camera.updateProjectionMatrix() 
-
+            
                         
                         displayMode = mode
-                        
+                         
                         
                         if(this.elDisplayModel){
                             this.elDisplayModel.value = mode == 'showPointCloud' ? ">>全景" : '>>点云'
@@ -488,7 +512,7 @@ export class Images360 extends EventDispatcher{
 	
 
 
-    flyToPano(toPano) {
+    flyToPano(toPano) {  //飞向漫游点
         if(toPano instanceof Panorama){
             toPano = {pano: toPano}
         }
@@ -498,10 +522,12 @@ export class Images360 extends EventDispatcher{
         }
         
         let done = (makeIt)=>{
+            //console.log('done '+ !!toPano.deferred)
             toPano.deferred && toPano.deferred.resolve(makeIt)
             makeIt && toPano.callback && toPano.callback()
         }
-        if(this.currentPano == pano && this.isAtPano() && !toPano.target ){
+        if(this.currentPano == toPano.pano && this.isAtPano() && !toPano.target ){
+            this.emit('flyToPano', toPano)
             return done(true);
         }
         if(this.flying){
@@ -518,14 +544,15 @@ export class Images360 extends EventDispatcher{
         var pano = toPano.pano 
         
         
-        var duration = toPano.duration || 300+Math.min(Potree.config.transitionsTime.flySpeed * this.position.distanceTo(pano.position),  Potree.config.transitionsTime.panoToPano )  
+        var duration = toPano.duration == void 0 ? (300+Math.min(Potree.config.transitionsTime.flySpeed * this.position.distanceTo(pano.position),  Potree.config.transitionsTime.panoToPano )) : toPano.duration 
         
         //console.warn("flyto "+pano.id + ' duration: ' + duration )     
         
         this.nextPano = pano
         //不飞的话是否不要执行这段?
         if(config.atPano.showSkybox || config.atPano.pointUsePanoTex){
-            if(this.checkAndWaitForPanoLoad(pano, "high", "low", this.basePanoSize, ()=> {
+            if(this.checkAndWaitForPanoLoad(pano,   this.basePanoSize, ()=> {
+                //console.log('setTimeout 1 flyToPano')
                     setTimeout( ()=>{
                         this.flyToPano(toPano)
                     },1)
@@ -575,8 +602,12 @@ export class Images360 extends EventDispatcher{
         const endPosition = pano.position.clone() 
         this.flying = true
         
+        {
+            toPano.duration = duration
+            toPano.easeName = easeName 
+            this.beforeFlyToPano(toPano)
+        }
         
-        this.beforeFlyToPano(pano,duration)
         
         viewer.scene.view.setView(endPosition, target ,duration,  ()=>{//done
             
@@ -590,10 +621,15 @@ export class Images360 extends EventDispatcher{
             this.currentPano = pano;
             this.flying = false 
             this.nextPano = null;
-            viewer.scene.pointclouds.forEach(e=>{
-                viewer.updateVisible(e, 'displayMode',pointcloudVisi) 
-            })
+            if(Potree.settings.displayMode == 'showPanos'){
+                viewer.scene.pointclouds.forEach(e=>{
+                    viewer.updateVisible(e, 'displayMode',pointcloudVisi) 
+                })
+            }
             done(true);
+            
+            this.emit('cameraMoveDone')
+            
         },(progress)=>{//onUpdate
             this.cube.material.uniforms.progress.value = progress 
             
@@ -602,29 +638,34 @@ export class Images360 extends EventDispatcher{
             })
         }, easeName )
         
-        {
-            toPano.duration = duration
-            toPano.easeName = easeName
-            this.emit('flyToPano', toPano)
-        }
+        
         
     }
 
-    beforeFlyToPano(pano, duration){
+
+
+
+
+
+
+    beforeFlyToPano(toPano){
         if(Potree.settings.displayMode == 'showPanos'){
             this.resetHighMap() 
         }
         
-        this.smoothZoomTo(1, duration / 2);  
-        
-                    
-       
-            
-        
-        
+        this.smoothZoomTo(1, toPano.duration / 2);  
+         
+         
+             
+        this.emit('flyToPano', toPano)
+         
     }
 
 
+
+
+
+
 	focusPano(toPano ){
 		if(this.currentPano !== null){
 			return this.flyToPano(toPano); 
@@ -658,7 +699,7 @@ export class Images360 extends EventDispatcher{
         var dur = toPano.duration == void 0 ? 700 : toPano.duration
         
         if(config.atPano.showSkybox){
-            if ( this.checkAndWaitForPanoLoad(pano, "low", "low", this.basePanoSize, ()=> {
+            if ( this.checkAndWaitForPanoLoad(pano,  this.basePanoSize, ()=> {
                     setTimeout( ()=>{
                         this.focusPano(toPano)
                     },1)
@@ -769,6 +810,7 @@ export class Images360 extends EventDispatcher{
             viewer.scene.view.setView(endPosition, null , duration,  ()=>{//done
                 viewer.scene.view.setView(currentPos, null , duration*5,  ()=>{//done
                     this.flying = !1 
+                    this.emit('cameraMoveDone')
                 },null,'easeInOutSine')
              
             } ,(progress)=>{//onUpdate
@@ -1022,7 +1064,7 @@ export class Images360 extends EventDispatcher{
     
     
     
-    
+    //等待部分加载完
     checkAndWaitForTiledPanoLoad(pano, basePanoSize, callback1, callback2, progressCallback, iswait, isclear, l) {
           
         if (!pano) {
@@ -1040,7 +1082,7 @@ export class Images360 extends EventDispatcher{
         
             
             var fov = {//test for direction  预加载的边缘有一丢丢不准确,尤其在相机倾斜时(4dkk也是)。
-                hFov: cameraLight.getHFOVForCamera(viewer.scene.getActiveCamera(), viewer.renderArea.clientWidth, viewer.renderArea.clientHeight),
+                hFov: cameraLight.getHFOVForCamera(viewer.scene.getActiveCamera(), viewer.mainViewport.resolution2.x,viewer.mainViewport.resolution2.y  /* viewer.renderArea.clientWidth, viewer.renderArea.clientHeight */),
 				vFov: viewer.scene.getActiveCamera().fov
             }//原先是null,不要求方向
             
@@ -1056,12 +1098,35 @@ export class Images360 extends EventDispatcher{
                 .bind(this));
 
             return !0;
-        }
+        } 
          
     } 
 
 
 
+    /* load(){//quickstart里的  
+		 
+        var lowSize = this.qualityManager.getPanoSize(PanoSizeClass.BASE),
+            highSize = this.qualityManager.getPanoSize(PanoSizeClass.STANDARD),
+            d = cameraLight.getHFOVForCamera(this.quickStartcamera, $('#player').width(), $('#player').height()),
+            p = this.quickStartcamera.fov,
+            r = Vectors.FORWARD.clone().applyQuaternion(this.view.quaternion) 
+         
+        var promise1 = this.view.pano.loadTiledPano(highSize, r, {
+            hFov: d,
+            vFov: p
+        }, !1, !1 , !0  ) 
+        var promise2 = this.view.pano.loadTiledPano(lowSize, r.clone().negate(), null, !1, !1, !0)
+        
+        this.loadPromise = this.pano.hasVideo ? promise2 : promise1;
+        //this.loadPromise = promise1;
+     
+    }        
+ */
+
+
+
+
 
     fitPanoTowardPoint(o){  //寻找最适合的点位
 		var point = o.point, 
@@ -1086,7 +1151,7 @@ export class Images360 extends EventDispatcher{
                 dis = /* size.x */ o.boundSphere.radius /* / 2 */ / THREE.Math.degToRad(hfov / 2)
             }
                 
-            bestDistance = dis*0.8 
+            bestDistance = dis//*0.8 
             
         } 
         
@@ -1123,7 +1188,11 @@ export class Images360 extends EventDispatcher{
     zoomTo(zoomLevel) {//缩放到某绝对zoomLevel
         let zoom = Potree.settings.zoom
         if (zoom.enabled) {
+            
+            
             zoomLevel = THREE.Math.clamp(zoomLevel, zoom.min, zoom.max)
+            //console.log(zoomLevel)
+            
             if(zoomLevel == this.zoomLevel) return;
                 
             /* if (zoomLevel > this.zoomLevel) {
@@ -1413,7 +1482,7 @@ Images360.prototype.checkAndWaitForPanoLoad = function() {
         return !1
     }
     
-    return function(pano, imgQuality1, imgQuality2, basePanoSize, doneFun1, doneFun2, progressCallback, iswait, isclear, p   ) {
+    return function(pano, basePanoSize, doneFun1, doneFun2, progressCallback, iswait, isclear, p   ) {
         if (overtime())
             return !0;
    
@@ -1456,7 +1525,7 @@ Images360.prototype.checkAndWaitForPanoLoad = function() {
 Images360.filters = { 
     inPanoDirection : function(pos, dir, i) { 
         return function(pano) {
-            if(dir instanceof Array){
+            if(dir instanceof Array){  
                 dir = dir.find(e=>e.datasetId == pano.pointcloud.dataset_id).direction; 
             } 
             var r = pano.floorPosition.clone().sub(pos).setZ(0).normalize()    //忽略上下角度,这样即使看得很低也能走
@@ -1537,6 +1606,7 @@ export class Images360Loader{
         center = {lat:center.y, lon:center.x} //中心点 
         
         Potree.loadPanos(center,(data)=>{
+            if(data.length == 0)console.error('没有漫游点')
             
             let images360 = new Images360(viewer, params);
             
@@ -1571,10 +1641,14 @@ export class Images360Loader{
                 images360.panos.forEach(pano=>{
                     panosBound.expandByPoint(pano.position)
                 }) 
+                let center = panosBound.getCenter(new THREE.Vector3)
+                let minBound = (new THREE.Box3()).setFromCenterAndSize(center, new THREE.Vector3(1,1,1))
+                panosBound.union(minBound)
+               
                 images360.bound = {
                     bounding:panosBound,
                     size: panosBound.getSize(new THREE.Vector3),
-                    center: panosBound.getCenter(new THREE.Vector3)
+                    center,
                 }
             }
 

+ 7 - 0
src/modules/Images360/Panorama.js

@@ -495,4 +495,11 @@ Panorama.prototype.loadTiledPano = function() {
     }
 }()
 
+
+/* 
+
+    经观察发现,navvis的也存在的问题是点云和全景有微小的偏差,导致远处的热点在全景和点云上看位置差别感大,比如一个在路上一个在天空上。
+
+
+ */
 export default Panorama

+ 11 - 3
src/modules/datasetAlignment/Alignment.js

@@ -50,7 +50,7 @@ var Alignment = {
          
         var matrix = new THREE.Matrix4().multiplyMatrices(pos2Matrix, rotMatrix);
         pointcloud.transformMatrix = matrix.clone();//为该数据集的变化矩阵。 对应navvis的m2w_
-        pointcloud.transformInvMatrix.getInverse(matrix)  
+        pointcloud.transformInvMatrix.copy(matrix).invert()
         pointcloud.rotateMatrix = rotMatrix
         pointcloud.panos.forEach(e=>e.transformByPointcloud())
         
@@ -69,7 +69,7 @@ var Alignment = {
         
     },
     rotate:function(pointcloud, deg, angle){//假设点云位移position后0,0,0就是它的中心了(根据navvis观察这样做是绕同一个点旋转的)
-        var angle = angle != void 0 ? angle : THREE.Math.degToRad(deg)
+        var angle = angle != void 0 ? angle : THREE.Math.degToRad(deg)   //正逆负顺
         pointcloud.orientationUser += angle
         Alignment.setMatrix(pointcloud)
     },
@@ -105,7 +105,7 @@ var Alignment = {
         this.originData.forEach(e=>{//恢复
             var pointcloud = viewer.scene.pointclouds.find(p=>p.dataset_id == e.id)
             this.translate(pointcloud, new THREE.Vector3().subVectors(e.translateUser , pointcloud.translateUser))
-            this.rotate(pointcloud,null, e.orientationUser - pointcloud.orientationUser)
+            this.rotate(pointcloud, null, e.orientationUser - pointcloud.orientationUser)
         })
         
         
@@ -165,7 +165,15 @@ var Alignment = {
     
 }
 
+/* 
 
+关于控制点:
+
+两个控制点只能打在同一个数据集上。传输这两个点的4dkk中的本地坐标和经纬度,后台算出该数据集的旋转平移,
+然后其他数据集绕该数据集旋转,并保持相对位置不变。
+
+
+ */
  
 
 export {Alignment} 

+ 2 - 1
src/navigation/FirstPersonControls.js

@@ -233,7 +233,7 @@ export class FirstPersonControls extends EventDispatcher {
                     camera.updateProjectionMatrix()
                 }
                 
-                console.log('zoom') 
+               
                 
             }else{
                 var direction = this.currentViewport.view.direction.clone();
@@ -287,6 +287,7 @@ export class FirstPersonControls extends EventDispatcher {
                 let s = FirstPersonControls.boundPlane.distanceToPoint(viewer.mainViewport.view.position)
                 s = Math.sqrt(s) / 10;
                 s = Math.max(FirstPersonControls.standardSpeed , s)
+                s  *= Potree.config.moveSpeedAdujust;
                 viewer.setMoveSpeed(s)
             }
             

+ 9 - 5
src/navigation/InputHandler.js

@@ -347,7 +347,7 @@ export class InputHandler extends EventDispatcher {
         
 		let consumed = false;
 		let consume = () => { return consumed = true; };
-		if (this.hoveredElements.length === 0) {
+		//if (this.hoveredElements.length === 0) {
 			/* for (let inputListener of this.getSortedListeners()) {
 				inputListener */this.viewer.dispatchEvent({
 					type: 'global_mouseup',
@@ -362,7 +362,8 @@ export class InputHandler extends EventDispatcher {
 					break;
 				} */
 			//}
-		}else{
+		//}
+        if (this.hoveredElements.length > 0) {        
 			let hovered = this.hoveredElements
 				.map(e => e.object)
 				.find(e => (e._listeners && e._listeners['mouseup']));
@@ -372,9 +373,11 @@ export class InputHandler extends EventDispatcher {
 					viewer: this.viewer,
 					consume: consume
 				});
-			}
-		}
-
+			} 
+        }
+        
+        
+        
 		if (this.drag) { 
             //拖拽结束
 			if (this.drag.object/*  && e.button == THREE.MOUSE.LEFT */) {//add LEFT
@@ -421,6 +424,7 @@ export class InputHandler extends EventDispatcher {
                                 drag: this.drag,
                                 viewer: this.viewer,
                                 pressDistance,
+                                viewport: this.hoverViewport,
                                 isAtDomElement: e.target == this.domElement,
                                 button: e.button //add
                             });

+ 128 - 72
src/navigation/RouteGuider.js

@@ -26,7 +26,7 @@ export class RouteGuider extends EventDispatcher{
         this.generateDeferred;
         viewer.addEventListener('loadPointCloudDone',this.init.bind(this))
         
-        
+        this.lastResult;//保存上一个的结果,以便于反向
     
     }
     init(){
@@ -97,7 +97,7 @@ export class RouteGuider extends EventDispatcher{
        
         //-------------map---------------------
         
-        this.mapMarkStart = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
+        /* this.mapMarkStart = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
             transparent:true, depthTest:false,
             map: texLoader.load(Potree.resourcePath+'/textures/map_instruction_start_route.png' )  
         }))
@@ -105,7 +105,7 @@ export class RouteGuider extends EventDispatcher{
             transparent:true, depthTest:false,
             map: texLoader.load(Potree.resourcePath+'/textures/map_instruction_target_reached.png' )  
         }))
-        this.mapMarkStart.renderOrder = this.mapMarkEnd.renderOrder = 2//在箭头之上
+        this.mapMarkStart.renderOrder = this.mapMarkEnd.renderOrder = 2//在箭头之上 */
         
         this.mapArrow = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
             transparent:true, depthTest:false,
@@ -118,12 +118,11 @@ export class RouteGuider extends EventDispatcher{
         
         
         
-        
-        this.mapMeshGroup.add(this.mapMarkStart)
-        this.mapMeshGroup.add(this.mapMarkEnd)
+        /* this.mapMeshGroup.add(this.mapMarkStart)
+        this.mapMeshGroup.add(this.mapMarkEnd) */
         this.mapMeshGroup.add(this.mapArrows)
         this.mapMeshGroup.name = 'mapRouteLayer'
-        this.mapMeshGroup.visible = /* this.mapMarkStart.visible = this.mapMarkEnd.visible = */ false
+        this.mapMeshGroup.visible = false
         
         viewer.mapViewer.emit('add',{object:this.mapMeshGroup, name:'route'})
         this.mapArrow.layers.mask = this.mapArrows.layers.mask // 修改成和map中的layer一样的
@@ -186,39 +185,39 @@ export class RouteGuider extends EventDispatcher{
     }
     
     
-    /* get routeStart(){
-        return this._routeStart && this._routeStart.clone()
-    }
+     
     
-    set routeStart(pos){ 
-        if(this._routeStart && pos && this._routeStart.equals(pos)) return //可能重复设置
-        this._routeStart = pos && new THREE.Vector3().copy(pos) 
-         
-        this.generateRoute()
-    }
     
-    get routeEnd(){
-        return this._routeEnd && this._routeEnd.clone() 
-    }
-    
-    set routeEnd(pos){ 
-        if(this._routeEnd && pos && this._routeEnd.equals(pos)) return 
-        this._routeEnd = pos && new THREE.Vector3().copy(pos)  
-        this.generateRoute()
-    } */
-    setRouteStart(pos, ifReset){
+    setRouteStart(pos, dealMapZ, ifReset){
         if(this.routeStart && pos && this.routeStart.equals(pos)) return //可能重复设置
         this.routeStart = pos && new THREE.Vector3().copy(pos) 
-        //    console.log('setRouteStart',ifReset,this.routeStart&&this.routeStart.toArray()) 
-        ifReset || this.generateRoute()
+        //if(dealMapZ && this.routeStart) this.routeStart.setZ(0)//后端要求设置为0,但设置后反而得不到了。直接用的是接近boundingbox.min.z的值
+            console.log('setRouteStart',ifReset,this.routeStart&&this.routeStart.toArray()) 
+       
+        if(ifReset){
+            this.bus && this.bus.emit('reposStartMarker', pos)
+        }else{
+            this.generateRoute()
+        }
+        
     }
-    setRouteEnd(pos, ifReset){ 
+    
+    
+    
+    setRouteEnd(pos, dealMapZ, ifReset){ 
         if(this.routeEnd && pos && this.routeEnd.equals(pos)) return 
         this.routeEnd = pos && new THREE.Vector3().copy(pos)
-        //    console.log('setRouteEnd',ifReset,this.routeEnd&&this.routeEnd.toArray())        
-        ifReset || this.generateRoute()
+        //if(dealMapZ && this.routeEnd) this.routeEnd.setZ(0)//后端要求设置为0
+            console.log('setRouteEnd',ifReset,this.routeEnd&&this.routeEnd.toArray())        
+        
+        if(ifReset){
+            this.bus && this.bus.emit('reposEndMarker', pos)
+        }else{
+            this.generateRoute()
+        }
     }
     
+    
     getSourceProjectionIndex(route) {//真正的起始
         var e = route.findIndex(function(t) {
             return t.instruction && t.instruction.type === 'source_projection_to_navgraph'
@@ -261,54 +260,53 @@ export class RouteGuider extends EventDispatcher{
             this.updateMapArrows() 
             this.displayRoute()
             
+            {
+                
+                const minBound = new THREE.Vector2(1,1)//针对垂直线,在地图上只有一个点
+                let bound = new THREE.Box2;
+                this.route.forEach(e=>{
+                    bound.expandByPoint(e)
+                })
+                let size = bound.getSize(new THREE.Vector2)
+                let margin = viewer.mapViewer.viewports[0].resolution2.clone().multiplyScalar(0.01)
+                size.add(margin)
+                let center = bound.getCenter(new THREE.Vector2)
+                
+                size.x = Math.max(size.x, minBound.x )
+                size.y = Math.max(size.y, minBound.y )
+                let duration = 1000
+                viewer.mapViewer.moveTo(center, size, duration)
+            }
             
-            this.generateDeferred && this.generateDeferred.resolve({dis:this.routeLength})
+            this.bus.emit('gotResult', {dis:this.routeLength})
+            /* this.generateDeferred && this.generateDeferred.resolve({dis:this.routeLength})
+            this.generateDeferred = null */
         }
         
         
         if(Potree.fileServer){
-            
-            let start = this.routeStart;
-            let end = this.routeEnd;
-            let startLonlat = viewer.transform.lonlatToLocal.inverse(start)
-            let endLonlat = viewer.transform.lonlatToLocal.inverse(end)
-            
-            var query = {
-                source_longitude: startLonlat.x,
-                source_latitude: startLonlat.y,
-                source_z: start.z,
-                destination_longitude: endLonlat.x,
-                destination_latitude: endLonlat.y,
-                destination_z: end.z
-            };
-            let url = `/laser/route/${Potree.settings.number}/getRoute?`
-            for(let i in query){
-                url+= (i + '='+ query[i] +'&')
-            }
-            
-            
-            Potree.fileServer.get(url).then((data)=>{
-                console.log(data.data)
-                if(!this.routeStart || !this.routeEnd)return 
+            let dealData = (data)=>{
                 
-                if(!data.data){
+                if(!data){
                     console.log('没有数据')
-                    return this.generateDeferred && this.generateDeferred.resolve('没有数据')
+                    this.bus && this.bus.emit('gotResult','没有数据')
+                    
+                    return //this.generateDeferred && this.generateDeferred.resolve()
                 }
                  
                   
                 this.clearRoute()
-                let length = data.data.length
+                let length = data.length
                 
                 if(length == 0){//可能距离太短
                     console.log('路径点数为0,直接取起点和终点连线')
                     this.route = [this.routeStart, this.routeEnd];
                 }else{ 
-                    let startIndex = this.getSourceProjectionIndex(data.data)
-                    let endIndex = this.getDestinationProjectionIndex(data.data)
+                    let startIndex = this.getSourceProjectionIndex(data)
+                    let endIndex = this.getDestinationProjectionIndex(data)
                     
                     
-                    let effectiveItems = data.data.slice(startIndex, endIndex + 1 );//只要点云范围内的点
+                    let effectiveItems = data.slice(startIndex, endIndex + 1 );//只要点云范围内的点
                     effectiveItems.forEach((item,i)=>{ 
                         let pos = viewer.transform.lonlatToLocal.forward(item.location.slice(0))
                         pos = new THREE.Vector3().fromArray(pos)
@@ -317,8 +315,8 @@ export class RouteGuider extends EventDispatcher{
                     
                     console.log(this.route)
                     
-                    this.setRouteStart(this.route[0],true) 
-                    this.setRouteEnd(this.route[this.route.length-1],true) 
+                    this.setRouteStart(this.route[0],false, true) 
+                    this.setRouteEnd(this.route[this.route.length-1],false,true) 
                 }
                 create()
                 /*
@@ -331,6 +329,62 @@ export class RouteGuider extends EventDispatcher{
                     longitude: 113.5957510575092
                     z: -1.12419
                 */
+            }
+            
+            
+            
+            
+            if(this.lastResult){
+                let data, use;  //直接用上次的结果
+                if(this.lastResult.routeStart.equals(this.routeStart) &&  this.lastResult.routeEnd.equals(this.routeEnd)){//和上次请求相同
+                    use = true
+                    data = this.lastResult.data
+                    
+                }else if(this.lastResult.routeStart.equals(this.routeEnd) &&  this.lastResult.routeEnd.equals(this.routeStart)){//..反向
+                    use = true
+                    data = this.lastResult.data.slice(0).reverse()
+                }
+                if(use){
+                    console.log('直接用上次的结果')
+                    return setTimeout(()=>{dealData(data)}, 1)//延迟是为了等待获得 RouteGuider.generateDeferred
+                     
+                    
+                }
+                
+            }
+            
+            
+            
+            
+            let start = this.routeStart.clone();
+            let end = this.routeEnd.clone();
+            let startLonlat = viewer.transform.lonlatToLocal.inverse(start)
+            let endLonlat = viewer.transform.lonlatToLocal.inverse(end)
+            
+            var query = {
+                source_longitude: startLonlat.x,
+                source_latitude: startLonlat.y,
+                source_z: start.z,
+                destination_longitude: endLonlat.x,
+                destination_latitude: endLonlat.y,
+                destination_z: end.z
+            };
+            let url = `/laser/route/${Potree.settings.number}/getRoute?`
+            for(let i in query){
+                url+= (i + '='+ query[i] +'&')
+            }
+            
+            Potree.fileServer.get(url).then((data)=>{
+                console.log(data.data)
+                if(!this.routeStart || !this.routeEnd)return 
+                
+                this.lastResult = {//保存数据
+                    routeStart : this.routeStart.clone(),
+                    routeEnd: this.routeEnd.clone(),
+                    data : data.data
+                }
+                
+                dealData(data.data)
                 
             })
             
@@ -368,8 +422,8 @@ export class RouteGuider extends EventDispatcher{
         
         var scale = 25/zoom
         this.mapArrow.scale.set(scale*0.6,scale*0.6,scale*0.6) 
-        this.mapMarkStart.scale.set(scale,scale,scale) 
-        this.mapMarkEnd.scale.set(scale,scale,scale) 
+        /* this.mapMarkStart.scale.set(scale,scale,scale) 
+        this.mapMarkEnd.scale.set(scale,scale,scale)  */
          
         
         if(ifReset){//因为缩放而重新排布箭头
@@ -384,16 +438,16 @@ export class RouteGuider extends EventDispatcher{
     
     displayRoute(o={}){
         if(!o.resetMap){ 
-            this.sceneMeshGroup.visible = true 
-            this.mapMeshGroup.visible = true
+            
             this.poleStart.position.copy(this.routeStart)
             this.poleEnd.position.copy(this.routeEnd)
-            this.mapMarkStart.position.copy(this.routeStart).setZ(0)
-            this.mapMarkEnd.position.copy(this.routeEnd).setZ(0)
+            /* this.mapMarkStart.position.copy(this.routeStart).setZ(0)
+            this.mapMarkEnd.position.copy(this.routeEnd).setZ(0) */
             this.scenePoints.forEach(e=>this.addArrow(e))
             this.arrows.children.forEach((e,i)=>this.setArrowDir(this.arrows.children,i));
         }
-           
+        this.sceneMeshGroup.visible = true 
+        this.mapMeshGroup.visible = true   
         this.mapPoints.forEach(e=>this.addMapArrow(e))
         this.mapArrows.children.forEach((e,i)=>this.setArrowDir(this.mapArrows.children,i));
         viewer.mapViewer.dispatchEvent({'type':'content_changed'})
@@ -415,11 +469,13 @@ export class RouteGuider extends EventDispatcher{
         mapArrows.forEach(e=>{
             this.mapArrows.remove(e)
         })
+        
+        this.sceneMeshGroup.visible = false 
+        this.mapMeshGroup.visible = false
     }
     
     clear(){//退出
-        this.sceneMeshGroup.visible = false 
-        this.mapMeshGroup.visible = false
+        console.log('导航clear') 
         this.routeStart = null
         this.routeEnd = null
         this.clearRoute()

+ 46 - 11
src/settings.js

@@ -77,30 +77,35 @@ const config = {//配置参数   不可修改
         flyOut:1000,
     }
     ,
+    moveSpeedAdujust : 0.3  //越小越慢
+    ,
     view:{
         fov:50,  //navvis:50 
         
     },
     
+     
+    
+    
     pointDensity:{
         panorama:{//显示全景时的漫游。因为点只能显示1个像素的大小,所以必须很密集,但又要限制点的数量
-            maxLevel: 8,
+            maxLevelPercent: 1,
             pointBudget :0.25*1000*1000,
         },
         fourViewports:{//分四屏时防止卡顿
-            maxLevel: 5,  
+            maxLevelPercent: 0.5,  
             pointBudget :0.25*1000*1000, // 只要限制这个就足够 (为什么分屏focus区域不同会闪烁,navvis不会)(navvis:maxLevel:5,pointBudget:1*1000*1000)
         },
         low:{//highPerformance
-            maxLevel: 4, //最小为0
+            maxLevelPercent: 0.5, //最小为0
             pointBudget :1*1000*1000,
         }, 
         middle:{//balanced  //不同场景相同级别所产生的numVisibleNodes和numVisiblePoints不同,如果分层比较细,可能要到level8才能看清,那么level5看到的点就很大且很少,如隧道t-e2Kb2iU
-            maxLevel: 5,
+            maxLevelPercent: 0.7,
             pointBudget:4*1000*1000,
         },
         high:{//highQuality
-            maxLevel: 12,//原本是8
+            maxLevelPercent: 1, 
             pointBudget:8*1000*1000,
         }
         //minNodeSize?
@@ -124,14 +129,16 @@ const config = {//配置参数   不可修改
         backColor:'#333333',
         guideLineColor:"#FFFFFF",
         lineWidth: 4,
-        labelOpacity:0.8,
+        labelOpacity:0.6,
         textColor: "#FFFFFF"
         
     },
     material:{//初始化
-        pointSize:0.75,//0.4,
+        pointSize:0.4,//0.75,//0.4, 相对大小
         minSize: 0.1,
-        pointSizeType: 'ADAPTIVE'//'ADAPTIVE' \ FIXED 'ATTENUATED'
+        maxSize: 10000,
+        pointSizeType: 'ATTENUATED', //'ADAPTIVE'//'ADAPTIVE' \ FIXED //ADAPTIVE的在小房间里大小会不太匹配,但在远景似乎更好
+        absolutePanoramaSize: 0.005,//全景漫游时的size
         //ADAPTIVE : 字会失真扭曲
         //'ATTENUATED' 往旁边看有缝隙、点在浮动
         //navvis的shader在哪里 为什么不会抖动
@@ -150,6 +157,7 @@ const config = {//配置参数   不可修改
         reticule: 3,
         measure:4,  
         magnifier:5, 
+        magnifierContent:16,
         volume:6,
         transformationTool:7,
         route:10,
@@ -218,7 +226,27 @@ const config = {//配置参数   不可修改
     
     clickMaxDragDis:5,
      
-    background: '#232323'    
+    background: '#232323',
+    mapBG:'#F5F5F5', //地图的clearColor
+
+    colors: {  //from navvis
+        red:  [213,0,0],
+        pink:  [197,17,98],
+        purple: [170,0,255],
+        "deep purple": [98,0,234],
+        blue: [ 41,98,255],
+        "light blue": [ 0,145,234],
+        cyan: [ 0,184,212],
+        teal: [ 0,191,165],
+        green: [0,200,83],
+        "light green": [ 100,221,23],
+        lime: [ 174,234,0],
+        yellow: [ 255,214,0],
+        amber: [ 255,171,0],
+        orange: [ 255,109,0],
+        "deep orange": [ 255,61,0],
+         
+    },
 }
 
 
@@ -248,13 +276,14 @@ let settings = {//设置   可修改
     ifShowMarker:true,//显示漫游点
     floorplanType:null,//平面图类型 'default' | 'diy'
     floorplanEnable:false,
+    mapEnable:true,//地图区域是否加载地图
     cameraFar : 10000, //相机最远范围 1-300
     //limitFar: true, //是否使用setting的cameraFar来限制(如在点云裁剪时为false)
     showPanoMesh:false, //显示小球,
     dblToFocusPoint:false,//调试时如果需要双击飞向某个点云的点,就打开。此时不在漫游点的话单击将无法漫游。//因和单击漫游冲突 
     
     unableNavigate : false,//进入如裁剪界面时 禁止漫游
-    
+    sizeFitToLevel: false,//当type为衰减模式时自动根据level调节大小。每长一级,大小就除以2
     zoom:{
         enabled : true,
         min:1,
@@ -270,6 +299,12 @@ let settings = {//设置   可修改
 
 
 settings.isLocalhost = settings.prefix.includes('localhost')
- 
 
+/* 
+    关于maxLevel:
+    viewer.scene.pointclouds[0].root.getLevel() 是 0
+    hierarchyStepSize是什么?见 if ((this.level % this.pcoGeometry.hierarchyStepSize) === 0 && this.hasChildren
+ 
+ 
+ */
 export {config, settings}

+ 6 - 0
src/utils.js

@@ -1256,6 +1256,12 @@ Utils.datasetPosTransform = {
     },
     fromDataset:function(o={}){
         let pointcloud = o.pointcloud || viewer.scene.pointclouds.find(e=>e.dataset_id == o.datasetId)
+        if(!pointcloud){
+            if(o.datasetId != void 0){
+                console.error(`datasetPosTransform找不到datasetId为${o.datasetId}的数据集,请检查(热点?测量线?)数据`)
+                //很可能是旧的热点,需要删除
+            }
+        }
         return pointcloud && (new THREE.Vector3).copy(o.dataset_location).applyMatrix4(pointcloud.transformMatrix)
     },
 }

+ 3 - 1
src/utils/Common.js

@@ -130,7 +130,9 @@ var Common = {
     CopyClassObject :function(targetObj,  copyObj){//复杂类对象
         for(let i in copyObj){
             if(i in copyObj.__proto__)break; //到函数了跳出 
-            if(copyObj[i].clone instanceof Function ){
+            if(!copyObj[i]){
+                targetObj[i] = copyObj[i];
+            }else if(copyObj[i].clone instanceof Function ){
                 targetObj[i] = copyObj[i].clone()
             }else{
                 targetObj[i] = copyObj[i];

+ 3 - 2
src/utils/DrawUtil.js

@@ -121,9 +121,10 @@ var LineDraw = {
             depthWrite:false,
             dashSize : o.dashSize || 0.1,
             gapSize: o.gapSize || 0.1,
-            
+               
             useDepth: !!o.useDepth,  
-            dashed: !!o.dashed
+            dashed: !!o.dashed,
+            dashWithDepth:!!o.dashWithDepth,//只在被遮住的部分显示虚线
            /*  transparent:o.dontAlwaysSeen ? false : true,
 			depthTest:o.dontAlwaysSeen ? true : false
              */

+ 21 - 5
src/utils/Magnifier.js

@@ -12,7 +12,7 @@ const magDistance_ = 2;//相机离目标位置的距离的分界线,当离得
 const radius_ = 0.2; //当相机离目标位置的距离>magDistance_时,希望看到的视野的半径
 const maxFov = THREE.Math.radToDeg(Math.atan(radius_ / magDistance_ )) * 2//提前计算出当相机离目标位置的距离<magDistance_时的fov,均使用=magDistance_时的fov。只要保证该fov大于主相机的fov就会有放大效果 
 const width2dPX = 200/1.4;//px
- 
+const sphereGeo = new THREE.SphereBufferGeometry(0.02,10,10);
 
 
 export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
@@ -24,7 +24,7 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
         
         
         this.viewport = new Viewport( null, this.camera, {
-            left:0, bottom:0, width:1, height: 1, name:'magnifier' 
+            left:0, bottom:0, width:1, height: 1, name:'magnifier' , cameraLayers:['magnifierContent']
         })
         this.viewport.setResolution(this.width, this.height,0,0)
         
@@ -62,8 +62,20 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
             depthTest: !1,
             //depthWrite: !1,
         }))
+        
+        this.targetPoint = new THREE.Mesh(sphereGeo, new THREE.MeshBasicMaterial({ 
+            color:"#ff0000",
+            transparent:true,
+            opacity:0.7,
+             
+        }))
+        this.targetPoint.name = 'magnifierPointTarget'
+        viewer.scene.scene.add(this.targetPoint)
+        viewer.setObjectLayers(this.targetPoint, 'magnifierContent' )
+        
         this.add(this.mesh)
         this.add(this.overlayMesh)
+        
         this.position.set(-1000,-1000,-100000)//令它看不见
         this.mesh.renderOrder = 10;
         this.overlayMesh.renderOrder = 11;
@@ -84,11 +96,14 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
         
         this.dontRender = false 
         viewer.addEventListener('global_drag', (e)=>{//拖拽时不渲染。主要是右键平移时渲染延迟了,会闪烁。 
-            this.dontRender = true
+            this.dontRender = true 
         })
         viewer.addEventListener('global_drop', (e)=>{
             this.dontRender = false
         })
+        viewer.addEventListener('global_mouseup', (e)=>{//测量时拖拽场景再mouseup
+            this.dontRender = false
+        })
         
         viewer.addEventListener('global_mousemove', (e)=>{
             if(e.hoverViewport == viewer.mainViewport){
@@ -182,8 +197,9 @@ export default class Magnifier extends THREE.Object3D {//放大镜or望远镜
         this.position.copy(playerPos.clone().add(dir))
          
 
-        this.aimPos =  aimPos
- 
+        this.aimPos = aimPos
+        this.targetPoint.position.copy(aimPos);
+        
         var scale = math.getScaleForConstantSize({// 
             width2d : width2dPX,
             camera:viewer.scene.getActiveCamera(),  position: this.getWorldPosition(new THREE.Vector3()),

+ 157 - 81
src/utils/Measure.js

@@ -40,6 +40,11 @@ const subLabelProp = {
 }
 
 
+const angle = THREE.Math.degToRad(5);//显示水平垂直辅助线的最小角度
+const guideShowMinAngle = {min: angle, max: Math.PI/2 - angle}
+
+   
+
     
  
 
@@ -71,10 +76,13 @@ export class Measure extends ctrlPolygon{
 		 
         //add:
         if(this.maxMarkers > 2 || this.faceDirection){
-            this.guideLine = this.createGuideLine();
-            this.add(this.guideLine) 
+            this.createGuideLine(); 
+        }
+        if(this.measureType == 'Distance'){
+            this.createHorVerGuideLine()
         }
         
+        
         this.selectStates = {}
         
         this.setUnitSystem(prop.unit || viewer.unitConvert.UnitService.defaultSystem)
@@ -104,6 +112,7 @@ export class Measure extends ctrlPolygon{
         let datasets = {}
         
         this.points_datasets.forEach(e=>{
+            if(e == void 0)return
             if(datasets[e]){
                 datasets[e] ++ 
             }else{
@@ -120,7 +129,7 @@ export class Measure extends ctrlPolygon{
         if(this.datasetId != old){
             this.dispatchEvent({type:'changeDatasetId'})
             if(this.datasetId == void 0){
-                this.dataset_points = null
+                this.dataset_points = null //可能为空或[null,null...]
             }else{
                 this.dataset_points = this.points.map(e=>{ 
                     return Potree.Utils.datasetPosTransform.toDataset({datasetId:this.datasetId, position:e.clone()})
@@ -147,7 +156,7 @@ export class Measure extends ctrlPolygon{
  
 	update(ifUpdateMarkers) { 
         super.update(ifUpdateMarkers)
-        
+      
         if(this.showCoordinates && this.points.length>0){
             let position = this.points[0];
        
@@ -174,9 +183,19 @@ export class Measure extends ctrlPolygon{
             return 
         }
          
-        let lastIndex = this.points.length - 1;
-            
-       
+         
+         
+        let setEdgeLabel = (label,p1,p2,distance)=>{//设置label位置和字
+            let center = new THREE.Vector3().addVectors(p1,p2).multiplyScalar(0.5);  
+            label.setPos(center) 
+            distance = distance == void 0 ? p1.distanceTo(p2) : distance; 
+            var text = viewer.unitConvert.convert(distance, 'distance', void 0, this.unitSystem, 0.1 , true)//distance要传0.1 这个factor
+            label.setText(text)
+            return distance
+        }
+         
+         
+        let lastIndex = this.points.length - 1; 
         for (let index = 0; index <= lastIndex; index++) {
             
             let nextIndex = (index + 1 > lastIndex) ? 0 : index + 1;
@@ -186,31 +205,46 @@ export class Measure extends ctrlPolygon{
             let nextPoint = this.points[nextIndex];
             let previousPoint = this.points[previousIndex];
 
-         
-         
-         
+          
             if(this.showDistances){ // edge labels
                 let edgeLabel = this.edgeLabels[index];
-
-                let center = new THREE.Vector3().add(point);
-                center.add(nextPoint);
-                center = center.multiplyScalar(0.5); 
-                edgeLabel.setPos(center) 
-                let distance = point.distanceTo(nextPoint);
-                
-                var text = viewer.unitConvert.convert(distance, 'distance', void 0, this.unitSystem, 0.1 , true)//distance要传0.1 这个factor
-
-                edgeLabel.setText(text)
-                 
+                let distance = point.distanceTo(nextPoint)
                 edgeLabel.shouldVisi = (index < lastIndex || this.closed && this.points.length > 2) && distance>0 
-                
-                
-                /* this.closed || */ edgeLabel.setVisible(edgeLabel.shouldVisi)  
-                 
+                /* this.closed || */edgeLabel.setVisible(edgeLabel.shouldVisi)  
+                if(edgeLabel.visible){
+                    setEdgeLabel(edgeLabel,point,nextPoint,distance)
+                }  
             }
-            
         } 
 
+        if(this.measureType == 'Distance' && this.points.length>1){//设置水平垂直辅助线
+            var pTop, pBtm
+            if(this.points[0].z > this.points[1].z ){
+                pTop = this.points[0];
+                pBtm = this.points[1];
+            }else{
+                pTop = this.points[1];
+                pBtm = this.points[0];
+            }
+            let projectPos = new THREE.Vector3(pTop.x, pTop.y, pBtm.z);//两条guideline的交点
+            
+            {//倾斜角度太小的时候不显示
+                let tan = pTop.distanceTo(projectPos) / pBtm.distanceTo(projectPos)
+                let angle = Math.atan(tan);
+           
+                this.shouldShowHorVerGuide = angle > guideShowMinAngle.min && angle < guideShowMinAngle.max    
+            }
+            
+            
+            LineDraw.updateLine(this.verGuideEdge, [pTop, projectPos]) 
+            LineDraw.updateLine(this.horGuideEdge, [pBtm, projectPos]) 
+            setEdgeLabel(this.verEdgeLabel,pTop,projectPos) 
+            setEdgeLabel(this.horEdgeLabel,pBtm,projectPos)  
+            
+            this.verGuideEdge.visible = this.horGuideEdge.visible = this.shouldShowHorVerGuide
+            this.verEdgeLabel.visible = this.horEdgeLabel.visible = this.shouldShowHorVerGuide
+        }
+         
         
         if(this.showArea && this.point2dInfo){ // update area 
            /*  if(this.points.length>2){
@@ -267,42 +301,10 @@ export class Measure extends ctrlPolygon{
         
         
         
-		if(this.showEdges){ // edge labels 
-            var className = 'measure_length';
-            if(this.closed){
-                className += ' sub'
-            }
-            /* let edgeLabel = new Label({
-                className , 
-            })
-            edgeLabel.setVisible(false)
-            if(!this.closed){
-                edgeLabel.elem.on('mouseover',()=>{
-                    this.setSelected(true, 'edgeLabel')
-                })
-                edgeLabel.elem.on('mouseout',()=>{
-                    this.setSelected(false, 'edgeLabel')
-                })
-            } */
-            
-            const edgeLabel = new TextSprite(
-                $.extend(this.closed ? subLabelProp : mainLabelProp,{sizeInfo: labelSizeInfo,  name:'edgeLabel'})
-            )
-            if(!this.closed){
-                edgeLabel.addEventListener('mouseover',()=>{
-                    this.setSelected(true, 'edgeLabel')
-                }) 
-                edgeLabel.addEventListener('mouseleave',()=>{
-                    this.setSelected(false, 'edgeLabel')
-                })  
-                edgeLabel.addEventListener('click',()=>{
-                    viewer.focusOnObject(this, 'measure')
-                })
-            }
-             
-            viewer.setObjectLayers(edgeLabel, 'measure' )
-			this.edgeLabels.push(edgeLabel);
-			this.add(edgeLabel);
+		if(this.showEdges){ // edge labels  
+            const edgeLabel = this.createEdgeLabel('edgeLabel', !this.closed) 
+			this.edgeLabels.push(edgeLabel); 
+			 
 		}
 
 		
@@ -349,13 +351,13 @@ export class Measure extends ctrlPolygon{
             this.editStateTimer = setTimeout(()=>{
                 if(!this.isEditing){
                     this.dispatchEvent({type:'editStateChange',state:false})   
-                    this.closed && this.edgeLabels.forEach(e=>e.setVisible(false) )
+                    this.setEdgesDisplay(false)
                 }
             },100)
         }else{
             if(!this.isEditing){
                 this.dispatchEvent({type:'editStateChange',state:true})   
-                this.closed && this.edgeLabels.forEach(e=>e.setVisible(e.shouldVisi)  )
+                this.setEdgesDisplay(true)
                 clearTimeout(this.editStateTimer)
             } 
         }
@@ -393,6 +395,15 @@ export class Measure extends ctrlPolygon{
     
     
     
+    setEdgesDisplay(state){
+        this.closed && this.edgeLabels.forEach(e=>e.setVisible(!!(state && e.shouldVisi))  )
+        
+        if(this.measureType == 'Distance'){
+            this.horEdgeLabel.visible = this.verEdgeLabel.visible = this.horGuideEdge.visible = this.verGuideEdge.visible = !!(state && this.shouldShowHorVerGuide)
+        }
+    }
+    
+    
     setSelected(state, hoverObject){//add
         
         hoverObject && (this.selectStates[hoverObject] = state)
@@ -411,38 +422,38 @@ export class Measure extends ctrlPolygon{
 			 
 			this.areaPlane && (this.areaPlane.material = planeMats.selected)
              
-            this.closed && this.edgeLabels.forEach(e=>e.setVisible(e.shouldVisi)  )
+            
             //this.areaLabel && this.areaLabel.elem.addClass('highLight')
             //this.closed || this.edgeLabels.forEach(e=>e.elem.addClass('highLight')  )
-            
+            this.setEdgesDisplay(true)
             
             this.areaLabel && setLabelHightState(this.areaLabel, true) 
             this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, true)  )
-             
-             
-            
-            
+              
         }else{
             this.markers.forEach(e=>this.setMarkerSelected(e,false,'selectAll' ))
             this.edges.forEach(e=>e.material = this.getLineMat('edgeDefault')  )
             this.areaPlane && (this.areaPlane.material = planeMats.default)
-            this.closed && this.edgeLabels.forEach(e=>e.setVisible( false))
+            this.setEdgesDisplay(false)
             //this.areaLabel && this.areaLabel.elem.removeClass('highLight')
             //this.closed || this.edgeLabels.forEach(e=>e.elem.removeClass('highLight')  )
             this.areaLabel && setLabelHightState(this.areaLabel, false) 
             this.closed || this.edgeLabels.forEach(e=>setLabelHightState(e, false)  )
             
         }
-          
+           
         this.selected = absoluteState
         viewer.mapViewer.emit('content_changed')
+        if(hoverObject != 'byList'){
+            this.bus && this.bus.emit('highlight', this.selected)//列表高亮
+        }
     }
     
 	removeMarker(index ){  
         super.removeMarker(index)
         
         this.points_datasets.splice(index, 1);
-        this.dataset_points.splice(index, 1)
+        this.dataset_points && this.dataset_points.splice(index, 1)
         this.coordinateLabels.splice(index, 1);
          
         let edgeIndex = index//(index === 0) ? 0 : (index - 1);
@@ -551,15 +562,60 @@ export class Measure extends ctrlPolygon{
      
     
     createGuideLine(){//add 辅助线 
-        var guideEdge = LineDraw.createFatLine([
+        var guideLine = LineDraw.createFatLine([
+            0, 0, 0,
+            0, 0, 0,
+        ],{material:this.getLineMat('guide')} )
+        guideLine.visible = false 
+        this.guideLine = guideLine
+        this.add(guideLine);
+    }
+    createHorVerGuideLine(){//创建水平与垂直辅助线,仅距离测量有。
+        var verGuideEdge = LineDraw.createFatLine([
+            0, 0, 0,
+            0, 0, 0,
+        ],{material:this.getLineMat('guide')} )
+        verGuideEdge.visible = false 
+        this.verGuideEdge = verGuideEdge
+        
+        var horGuideEdge = LineDraw.createFatLine([
             0, 0, 0,
             0, 0, 0,
         ],{material:this.getLineMat('guide')} )
-        guideEdge.visible = false 
+        horGuideEdge.visible = false 
+        this.horGuideEdge = horGuideEdge
+        
+        this.add(this.verGuideEdge);
+        this.add(this.horGuideEdge);
+        
+        
+        //label:
+        this.verEdgeLabel = this.createEdgeLabel('verGuideEdge')  
+        this.horEdgeLabel = this.createEdgeLabel('horGuideEdge') 
+
         
-        return guideEdge;
     }
     
+    createEdgeLabel(name, hasHoverEvent){
+        const edgeLabel = new TextSprite(
+            $.extend(hasHoverEvent ? mainLabelProp : subLabelProp,{sizeInfo: labelSizeInfo,  name:name||'edgeLabel'})
+        )
+        if(hasHoverEvent){
+            edgeLabel.addEventListener('mouseover',()=>{
+                this.setSelected(true, 'edgeLabel')
+            }) 
+            edgeLabel.addEventListener('mouseleave',()=>{
+                this.setSelected(false, 'edgeLabel')
+            })  
+            edgeLabel.addEventListener('click',()=>{
+                viewer.focusOnObject(this, 'measure')
+            })
+        }
+        edgeLabel.visible = false
+        viewer.setObjectLayers(edgeLabel, 'measure' )
+        this.add(edgeLabel)
+        return edgeLabel
+    }
     
     createAreaLabel(){ 
         /* const areaLabel = new Label({
@@ -629,7 +685,11 @@ export class Measure extends ctrlPolygon{
                     dashSize: 0.5, 
                     gapSize: 0.2, 
                     linewidth: config.measure.lineWidth,
-                    useDepth :true                   
+                    useDepth :true,
+                    dashWithDepth :true,  // 只在被遮住的部分显示虚线,因为实线容易挡住label
+                    dashed :true,   
+                    dashSize : 0.04,
+                    gapSize: 0.04,                    
                 }),
                 edgeSelect:  LineDraw.createFatLineMat({
                     color: highLightColor,//'#f0ff00',
@@ -711,13 +771,15 @@ export class Measure extends ctrlPolygon{
             prop.maxMarkers = 2,
             prop.minMarkers = 2,
             prop.faceDirection = "vertical" 
+            prop.unableDragAtMap = true
         }else if(prop.measureType == 'Hor Distance'){
             prop.showDistances = true,  
             prop.closed = false,
             prop.showEdges = true,
             prop.maxMarkers = 2,
             prop.minMarkers = 2,
-            prop.faceDirection = "horizontal"   
+            prop.faceDirection = "horizontal"  
+                   
         }else if(prop.measureType == 'Area'){
             prop.showDistances = true,  
             prop.showArea = true,  
@@ -731,13 +793,15 @@ export class Measure extends ctrlPolygon{
             prop.closed = true, 
             prop.minMarkers = 3  
             prop.faceDirection = "horizontal"
+             
         }else if(prop.measureType == 'Ver Area'){
             prop.showDistances = true,  
             prop.showArea = true,  
             prop.showEdges = true,
             prop.closed = true, 
             prop.minMarkers = 3 
-            prop.faceDirection = "vertical"            
+            prop.faceDirection = "vertical"   
+            prop.unableDragAtMap = true            
         }else if(prop.measureType == 'Rect Area'){
             prop.showDistances = true,  
             prop.showArea = true,  
@@ -753,7 +817,7 @@ export class Measure extends ctrlPolygon{
             prop.minMarkers = 4 
             prop.maxMarkers = 4 
             prop.isRect = true 
-            prop.faceDirection = "horizontal"  
+            prop.faceDirection = "horizontal" 
         }else if(prop.measureType == 'Ver Rect Area'){
             prop.showDistances = true,  
             prop.showArea = true,  
@@ -763,6 +827,7 @@ export class Measure extends ctrlPolygon{
             prop.maxMarkers = 4 
             prop.isRect = true 
             prop.faceDirection = "vertical"  
+            prop.unableDragAtMap = true
         } 
     }
 
@@ -782,7 +847,18 @@ export class Measure extends ctrlPolygon{
     }
 
 
-
+    reDraw(restMarkerCount=0){//重新开始画 
+        super.reDraw(restMarkerCount)
+        if(this.measureType == 'Distance'){
+            this.shouldShowHorVerGuide = false
+            this.setEdgesDisplay(false)
+        }
+        if(this.showArea){ 
+            this.area = {value:0};
+            this.areaLabel && this.areaLabel.setVisible(false)
+        }
+    }
+    
 
 
 	/* get showCoordinates () {

+ 27 - 14
src/utils/MeasuringTool.js

@@ -414,16 +414,7 @@ export class MeasuringTool extends EventDispatcher{
                     //this.viewer.scene.removeMeasurement(measure)
                     //cancelFun && cancelFun()
                     //重新开始画
-                    let pointCount = measure.points.length
-                    while(pointCount > 0){
-                        measure.removeMarker(--pointCount)
-                    }
-                       
-                    if(measure.showArea){
-                        measure.point2dInfo = null
-                        measure.area = {value:0};
-                        measure.areaLabel && measure.areaLabel.setVisible(false)
-                    }
+                    measure.reDraw()
                     
                     
                     this.viewer.addEventListener('global_click', click, 10)
@@ -447,7 +438,11 @@ export class MeasuringTool extends EventDispatcher{
 			this.viewer.removeEventListener('cancel_insertions', Exit);
             //pressExit && this.viewer.inputHandler.removeEventListener('keydown', pressExit);
             this.viewer.removeEventListener('global_click', click)
-            e.remove || callback && callback() 
+            this.viewer.removeEventListener('global_mousemove', ifAtWrongPlace) 
+            viewer.dispatchEvent({
+                type : "CursorChange", action : "remove",  name:"polygon_AtWrongPlace"
+            });
+            e.remove || callback && callback()  
             /* this.viewer.dispatchEvent({
                 type: 'finish_inserting_measurement',
                 measure: measure
@@ -456,6 +451,10 @@ export class MeasuringTool extends EventDispatcher{
 
         
         let Exit = (e)=>{//强制退出
+        
+            if(e.measure && e.measure != measure){
+                return;//若指定了退出的measure但和该measure不一致,就返回
+            }
             console.log('Exit: ' +  measure.id)
             if(e.remove){
                 viewer.scene.removeMeasurement(measure)  
@@ -491,8 +490,8 @@ export class MeasuringTool extends EventDispatcher{
 		  
           
                  
-        let click = (e)=>{
-            
+        let click = (e)=>{//一旦点击就立刻增加两marker
+            if(measure.unableDragAtMap && e.viewport.name == 'mapViewport' )return 
             var marker = measure.addMarker({point:new THREE.Vector3(0, 0, 0)})
             this.viewer.inputHandler.startDragging(marker , {endDragFun, notPressMouse:true} ); //notPressMouse代表不是通过按下鼠标来拖拽
             e.drag = this.viewer.inputHandler.drag
@@ -508,7 +507,21 @@ export class MeasuringTool extends EventDispatcher{
         }
         this.viewer.addEventListener('global_click', click, 10)//add importance:10
             
-          
+        let ifAtWrongPlace = (e)=>{
+            if(measure.unableDragAtMap && e.hoverViewport.name == 'mapViewport' ){
+                viewer.dispatchEvent({
+                    type : "CursorChange", action : "add",  name:"polygon_AtWrongPlace"
+                });
+            }else{
+                viewer.dispatchEvent({
+                    type : "CursorChange", action : "remove",  name:"polygon_AtWrongPlace"
+                });
+            }
+        }
+        if(measure.unableDragAtMap){ 
+            this.viewer.addEventListener('global_mousemove', ifAtWrongPlace) 
+        }
+        
         
 		this.viewer.scene.addMeasurement(measure);
         

+ 18 - 14
src/utils/TransformationTool.js

@@ -9,7 +9,7 @@ const OpaWhenNotSelect = 0.75
 const ScaleRatio = 4
 const OutlineColor = 0x666666
 //----------------------------------------
-
+const hideFocusHandles = true//add
 
 
 export class TransformationTool {
@@ -68,7 +68,7 @@ export class TransformationTool {
 			"rotation.y": {name: "rotation.y", node:  new THREE.Object3D(), color: green, alignment: [0, 1, 0]},
 			"rotation.z": {name: "rotation.z", node:  new THREE.Object3D(), color: blue, alignment: [0, 0, 1]},
 		};
-		this.handles = Object.assign({}, this.scaleHandles, this.focusHandles, this.translationHandles, this.rotationHandles);
+		this.handles = Object.assign({}, this.scaleHandles,    hideFocusHandles?{}:this.focusHandles, this.translationHandles, this.rotationHandles);
 		this.pickVolumes = [];
 
 		this.initializeScaleHandles();
@@ -188,6 +188,7 @@ export class TransformationTool {
 	}
 
 	initializeFocusHandles(){
+        if(hideFocusHandles)return//add
 		//let sgBox = new THREE.BoxGeometry(1, 1, 1);
 		let sgPlane = new THREE.PlaneGeometry(4, 4, 1, 1);
 		let sgLowPolySphere = new THREE.SphereGeometry(1, 16, 16);
@@ -309,6 +310,7 @@ export class TransformationTool {
 	}
 
 	initializeTranslationHandles(){
+
 		let boxGeometry = new THREE.BoxGeometry(1, 1, 1);
 
 		for(let handleName of Object.keys(this.translationHandles)){
@@ -675,14 +677,16 @@ export class TransformationTool {
 			}
 		}
 
-		for(let handleName of Object.keys(this.focusHandles)){
-			let handle = this.focusHandles[handleName];
+		if(!hideFocusHandles){
+            for(let handleName of Object.keys(this.focusHandles)){
+                let handle = this.focusHandles[handleName];
 
-			if(this.activeHandle === handle){
-				handle.node.setOpacity(1.0);
-			}else{
-				handle.node.setOpacity(OpaWhenNotSelect)
-			}
+                if(this.activeHandle === handle){
+                    handle.node.setOpacity(1.0);
+                }else{
+                    handle.node.setOpacity(OpaWhenNotSelect)
+                }
+            }
 		}
 
 		for(let handleName of Object.keys(this.translationHandles)){
@@ -712,11 +716,11 @@ export class TransformationTool {
 
 			if(this.activeHandle === handle){
 				handle.node.setOpacity(1.0);
-
-				let relatedFocusHandle = this.focusHandles[handle.name.replace("scale", "focus")];
-				let relatedFocusNode = relatedFocusHandle.node;
-				relatedFocusNode.setOpacity(OpaWhenNotSelect);
-
+                if(!hideFocusHandles){
+                    let relatedFocusHandle = this.focusHandles[handle.name.replace("scale", "focus")];
+                    let relatedFocusNode = relatedFocusHandle.node;
+                    relatedFocusNode.setOpacity(OpaWhenNotSelect);
+                }
 				for(let translationHandleName of Object.keys(this.translationHandles)){
 					let translationHandle = this.translationHandles[translationHandleName];
 					translationHandle.node.setOpacity(OpaWhenNotSelect);

+ 8 - 4
src/viewer/EDLRenderer.js

@@ -204,8 +204,10 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
         }
         
         //skybox 
-        viewer.setCameraLayers(camera, ['skybox'])
-        viewer.renderer.render(viewer.scene.scene, camera);
+        if(!params.magnifier){
+            viewer.setCameraLayers(camera, ['skybox'])
+            viewer.renderer.render(viewer.scene.scene, camera);
+        }
          
         
         //pointcloud
@@ -261,7 +263,7 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
 		viewer.dispatchEvent({type: "render.pass.scene", viewer: viewer/* , renderTarget: this.rtRegular */});
 		viewer.renderer.setRenderTarget(params.target || null);
         
-        viewer.scene.pointclouds.forEach(e=>{
+        if(!params.magnifier)viewer.scene.pointclouds.forEach(e=>{//放大镜显示点云
             e.visible = e.oldVisi
         })
         
@@ -305,7 +307,9 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
         }   
           
 		//viewer.dispatchEvent({type: "render.pass.end",viewer: viewer});
-        
+        viewer.scene.pointclouds.forEach(e=>{
+            e.visible = e.oldVisi
+        })
         
 	}
 }

+ 6 - 0
src/viewer/View.js

@@ -13,6 +13,9 @@ export class View{
 		this.maxPitch = Math.PI / 2;
 		this.minPitch = -Math.PI / 2;
         this.zoom = 1
+        
+        
+
 	}
     
     applyToCamera(camera){//add
@@ -28,6 +31,9 @@ export class View{
         
     }
     
+    
+    
+    
     copy(a){
         Common.CopyClassObject(this, a)
     }

+ 181 - 42
src/viewer/viewer.js

@@ -72,7 +72,7 @@ export class Viewer extends ViewerBase{
             
         }
         
-        
+        this.testingMaxLevel = true
         
         //add -------- 
         this.navigateMode = 'free' // 'panorama'; 'free'自由模式是只显示点云或者未进入到漫游点, 
@@ -421,14 +421,34 @@ export class Viewer extends ViewerBase{
                     return pointDensity
                 },
                 set: (density)=>{
-                    if(pointDensity != density){
+                    if(density){  
                         var config = Potree.config.pointDensity[density];
                         viewer.setPointBudget(config.pointBudget );
-                        Potree.maxPointLevel = config.maxLevel
+                        //Potree.maxPointLevel = config.maxLevel
                         viewer.scene.pointclouds.forEach(e=>{
-                            e.maxLevel = config.maxLevel
+                            if(viewer.testingMaxLevel){
+                                e.maxLevel = 12;//先加载到最大的直到测试完毕。由于5个level为一组来加载,所以如果写4最高能加载到5,如果写5最高能加载到下一个级别的最高也就是10
+                                //console.log('maxLevel: '+e.maxLevel +  ' testingMaxLevel中 '  )                                
+                            }else{
+                                e.maxLevel = Math.floor(config.maxLevelPercent * e.nodeMaxLevel); 
+                                //console.log('maxLevel: '+e.maxLevel +  '  ( density : '+density);
+                                
+                                if(Potree.settings.sizeFitToLevel){
+                                    e.changePointSize() 
+                                } 
+                                e.changePointOpacity()
+                            } 
+                            
+                           
                         }) 
                         pointDensity = density
+                        /* if(!viewer.testingMaxLevel && Potree.sdk){
+                            Potree.sdk.scene.changePointSize()
+                            Potree.sdk.scene.changePointOpacity()
+                        } */
+                        
+                        
+                        
                     }
                 }
             })
@@ -448,7 +468,30 @@ export class Viewer extends ViewerBase{
                 }
             })
             
-            
+            this.on('updateNodeMaxLevel',(pointcloud,nodeMaxLevel)=>{
+                
+                if(!viewer.testNodeLevelTimer && viewer.testingMaxLevel  ){
+                    viewer.testNodeLevelTimer = setTimeout(()=>{//先加载一段时间最高level的点云。但希望不会刚好附近的点云都没有达到最高的level,否则就要走一段才能了。
+                        viewer.testingMaxLevel = false
+                        console.log('结束testingMaxLevel')
+                        Potree.settings.pointDensity = Potree.settings.pointDensity 
+                    },3000) 
+                    viewer.beginTestTime = Date.now()
+                }
+                console.log('updateNodeMaxLevel ' +  pointcloud.dataset_id + " : "+ nodeMaxLevel)                
+                if(nodeMaxLevel >= 10 && viewer.testingMaxLevel){//10的时候差不多能加载到11和12了。假设最高只有12的话,就到10就可以。不过大多数场景都到不了10,也不知有没有大于10的,如果没有,这里可以写5.
+                    viewer.testingMaxLevel = false
+                    console.log('提前结束testingMaxLevel,用时:'+(Date.now()-viewer.beginTestTime))
+                    //我的电脑用时大概1500
+                }
+                Potree.settings.pointDensity = Potree.settings.pointDensity //重新计算
+                if(!Potree.settings.sizeFitToLevel){
+                    pointcloud.changePointSize()
+                    
+                }
+                
+                //见过最小加载到的nodeMaxLevel是4
+            })
             
         }
         {
@@ -476,6 +519,10 @@ export class Viewer extends ViewerBase{
         
 	}
 
+    
+
+
+
 	onCrash(error){
 
 		$(this.renderArea).empty();
@@ -2336,6 +2383,7 @@ export class Viewer extends ViewerBase{
             //if(!params.target){
                 params.camera = params.camera || view.camera;
                 params.extraEnableLayers = view.extraEnableLayers
+                params.cameraLayers = view.cameraLayers
             //}
             
             if(!view.active)return
@@ -2443,10 +2491,14 @@ export class Viewer extends ViewerBase{
         
         
         
-        if(!params.magnifier){//为什么要在点云之后渲染,否则透明失效 、 会被点云覆盖 
-            this.setCameraLayers(camera, ['sceneObjects','marker','reticule','route',/* 'bothMapAndScene' */], params.extraEnableLayers) //透明贴图层 skybox 、reticule marker 不能遮住测量线
+         //为什么要在点云之后渲染,否则透明失效 、 会被点云覆盖 
+         
+        let cameraLayers = params.cameraLayers || ['sceneObjects','marker','reticule','route',/* 'bothMapAndScene' */];
+        if(cameraLayers.length){
+            this.setCameraLayers(camera,  cameraLayers, params.extraEnableLayers) //透明贴图层 skybox 、reticule marker 不能遮住测量线
             this.renderer.render(this.scene.scene, camera); 
-        } 
+        }
+          
         this.dispatchEvent({type: "render.pass.scene", viewer: viewer});
     
         //清除深度 !!!!
@@ -2570,16 +2622,29 @@ export class Viewer extends ViewerBase{
 
 
 
-    startScreenshot(info={},  width=800, height=400, compressRatio){//add
     
+
+    startScreenshot(info={},  width=800, height=400, compressRatio){//add
+        let deferred = info.deferred || $.Deferred();
+        
+        if(this.images360.flying){//如果在飞,飞完再截图
+            info.deferred = deferred
+            this.images360.once('cameraMoveDone', this.startScreenshot.bind(this,  info,  width, height, compressRatio))
+            return deferred.promise()
+        }
+        
+        var sid = Date.now()
+        //抗锯齿待加 1 post处理 2截图大张再抗锯齿缩小
     
-    //抗锯齿待加 1 post处理 2截图大张再抗锯齿缩小
-    
-         
+        console.log('startScreenshot: '+sid)
+        
         
-        let deferred = $.Deferred();
         
         var screenshot = ()=>{
+            
+            viewer.mapViewer.needRender = true 
+            
+            
             var { buffer  } = this.makeScreenshot( new THREE.Vector2(width,height)  );
         
             var dataUrl = Potree.Utils.pixelsArrayToDataUrl(buffer, width, height, compressRatio)
@@ -2587,10 +2652,14 @@ export class Viewer extends ViewerBase{
             if(!Potree.settings.isOfficial){
                 Common.downloadFile(dataUrl, 'screenshot.jpg') 
             } 
-            deferred.resolve(dataUrl)
             
             
             
+            var finish = ()=>{
+                deferred.resolve(dataUrl)
+                console.log('screenshot done: '+sid)
+            }
+            
             {//恢复:
                 
                 if(info.type == 'measure'){
@@ -2604,12 +2673,17 @@ export class Viewer extends ViewerBase{
             
                 if(oldStates.attachedToViewer != this.mapViewer.attachedToViewer){
                     if(info.type == 'measure'){
-                        this.mapViewer.attachToMainViewer(false)
+                        this.mapViewer.attachToMainViewer(false ) 
                     } 
                 }
                 mapViewport.camera.zoom = oldStates.mapZoom
+                mapViewport.camera.updateProjectionMatrix()        
                 
-                
+                if(Potree.settings.displayMode == 'showPanos') {
+                    viewer.images360.flyToPano({pano:oldStates.pano, duration:0, callback:()=>{
+                        finish()
+                    }}) 
+                }
                 
                 oldStates.viewports.forEach(old=>{//恢复相机
                     var viewport = [mapViewport, mainViewport].find(v=>v.name == old.name);
@@ -2629,8 +2703,16 @@ export class Viewer extends ViewerBase{
                         camera: viewport.camera,
                         viewport : viewport
                     }) 
-                })  
+                }) 
+                        
             } 
+            
+            
+            if(Potree.settings.displayMode != 'showPanos') {
+                finish()
+            }
+            
+            
         }
         
         let mapViewport = this.mapViewer.viewports[0]
@@ -2640,30 +2722,34 @@ export class Viewer extends ViewerBase{
             viewports : [mapViewport, mainViewport].map(e=>{
                 return  e.clone()  
             }),
-            mapZoom: mapViewport.camera.zoom
+            mapZoom: mapViewport.camera.zoom,
+            pano: Potree.settings.displayMode == 'showPanos' ? viewer.images360.currentPano : null,
         }
-        //令漫游点不可见
-        this.images360.panos.forEach(pano=>{
+         
+        
+        
+        
+        this.images360.panos.forEach(pano=>{//令漫游点不可见
             viewer.updateVisible(pano, 'screenshot', false)
-        })
-        //令reticule不可见
-        viewer.updateVisible(this.reticule, 'screenshot', false)
-        //令mapCursor不可见
-        viewer.updateVisible(this.mapViewer.cursor, 'screenshot', false)
+        }) 
+                              
+        viewer.updateVisible(this.reticule, 'screenshot', false)//令reticule不可见 
+                               
+        viewer.updateVisible(this.mapViewer.cursor, 'screenshot', false)//令mapCursor不可见
         
         
         if(info.type == 'measure'){//要截图双屏 
             this.scene.measurements.forEach(e=>this.updateVisible(e,'screenshot',e == info.measurement)  )
              
             
-            this.mapViewer.attachToMainViewer(true, 'measure', 0.5)
+            this.mapViewer.attachToMainViewer(true, 'measure', 0.5  )//不要移动相机去适应
            
             viewer.updateScreenSize({forceUpdateSize:true, width, height}) //更新viewports相机透视
             
             //不同角度截图 得到三维的会不一样,因为focusOnObject是根据方向的
             let promise = this.focusOnObject(info.measurement, 'measure', 0, /*  {mapDont:true} */)
             promise.done(()=>{ 
-                 
+                console.log('promise.done') 
                 this.viewports.forEach(e=>{
                     e.view.applyToCamera(e.camera)
                      
@@ -2675,8 +2761,30 @@ export class Viewer extends ViewerBase{
                     
                 }) 
                 
-                this.mapViewer.waitLoadDone(screenshot.bind(this))//等待地图所有加载完
-                  
+                let waitMap = ()=>{
+                    console.log('waitMap: '+sid)
+                    this.mapViewer.waitLoadDone(screenshot.bind(this))//等待地图所有加载完
+                    
+                } 
+                
+                
+                /* if(Potree.settings.displayMode == 'showPanos'){//如果是全景图,要等全景的tile加载完 
+                    //this.images360.checkAndWaitForTiledPanoLoad(this.images360.currentPano, this.images360.qualityManager.standardSize, ()=>{//done
+                    //loadTiledPano
+                    if(!this.images360.checkAndWaitForPanoLoad(this.images360.currentPano,  this.images360.qualityManager.standardSize,   ()=>{//done   
+                        //standardSize maxNavPanoSize
+                        waitMap()
+                    })){
+                        waitMap()
+                    }
+                }else{
+                    waitMap()
+                }  */  //512就可以
+                
+                
+                //调不通,暂时先用setTimeout
+                 
+                setTimeout(waitMap.bind(this), 300)
             })
             
         }else{
@@ -2691,9 +2799,12 @@ export class Viewer extends ViewerBase{
         
     }
     
-    
+
     focusOnObject(object, type, duration, o={} ) {
         //飞向热点、测量线等 。
+        
+        
+        
         let deferred = $.Deferred();
         let target  = new THREE.Vector3,
             position = new THREE.Vector3, 
@@ -2709,11 +2820,17 @@ export class Viewer extends ViewerBase{
             cameraTemp.lookAt(target);
             cameraTemp.updateMatrix();
             cameraTemp.updateMatrixWorld();
+            //原始的bound
+            let boundOri = new THREE.Box3() 
+            object.points.forEach(e=>{ 
+                boundOri.expandByPoint(e)
+            })
+            let boundSizeOri = boundOri.getSize(new THREE.Vector3)
+            
+            //对镜头的bound
             var inv = cameraTemp.matrixWorldInverse;
            
-            let bound = new THREE.Box3() 
-            
-          
+            let bound = new THREE.Box3()  
             object.points.forEach(e=>{
                 var p = e.clone().applyMatrix4(inv);
                 bound.expandByPoint(p)
@@ -2746,22 +2863,33 @@ export class Viewer extends ViewerBase{
             }//为何在只有两点的情况下,依然不能使box的边界刚好对着屏幕边界? 会缩小一些。  而三点以上的中心在这个视角上也不准确,所以点会超出box范围。
              
             
-            if(o.mapDont || this.mapViewer.attachedToViewer){ 
-                this.mapViewer.fitToBound(target.clone(), boundSize.clone().multiplyScalar(2), duration)
+            if(this.mapViewer.attachedToViewer){ 
+                //console.log('mapFocusOn: '+target.toArray())
+                const minBound = new THREE.Vector2(1,1)//针对垂直线,在地图上只有一个点
+                let boundSizeMap = boundSizeOri.clone().multiplyScalar(2)
+                boundSizeMap.x = Math.max(minBound.x, boundSizeMap.x )
+                boundSizeMap.y = Math.max(minBound.y, boundSizeMap.y )
+                this.mapViewer.moveTo(target.clone(), boundSizeMap, duration)
             }
             
             
-            if(Potree.settings.displayMode == 'showPointCloud'){  
+            if(Potree.settings.displayMode == 'showPointCloud'){  //点云
                 let dir = new THREE.Vector3().subVectors(camera.position, target).normalize() 
                 position.copy(target).add(dir.multiplyScalar(dis))
                  
-            }else if(Potree.settings.displayMode == 'showPanos'){
+            }else if(Potree.settings.displayMode == 'showPanos'){//全景 (比较难校准)
                 let pano = viewer.images360.fitPanoTowardPoint({
-                    point : target,
-                    bestDistance : dis * 0.5 //乘以小数是为了尽量靠近
+                    point : target, 
+                    //bestDistance : dis * 0.5, //乘以小数是为了尽量靠近 
+                    boundSphere: boundOri.getBoundingSphere(new THREE.Sphere),
                 })
-                pano && viewer.images360.flyToPano({pano, target, duration, deferred })
+                pano && viewer.images360.flyToPano({pano, target, duration, deferred, dontMoveMap:true })//dontMoveMap不要移动map,否则flytopano会自动在map中focus到漫游点的位置,而非测量线了
+                
+                if(!pano){
+                    console.error('no pano')
+                }
                 return deferred
+                //出现过到达位置后测量线标签闪烁的情况
             }
             
         } else if (type == 'tag') {
@@ -2769,6 +2897,11 @@ export class Viewer extends ViewerBase{
             target.copy(object.position)
             const bestDistance = 2
             
+            { 
+                //console.log('mapFocusOn: '+target.toArray()) 
+                this.mapViewer.moveTo(target.clone(), null, duration)
+            }
+            
             if(Potree.settings.displayMode == 'showPointCloud'){ 
                 dis = bestDistance
                 let dir = new THREE.Vector3().subVectors(camera.position, target).normalize() 
@@ -2779,7 +2912,7 @@ export class Viewer extends ViewerBase{
                     point : target,
                     bestDistance  //越近越好,但不要太近,bestDistance左右差不多
                 })
-                pano && viewer.images360.flyToPano({pano, target, duration, deferred })
+                pano && viewer.images360.flyToPano({pano, target, duration, deferred, dontMoveMap:true  })
                 return deferred                
             }
         }
@@ -3021,7 +3154,13 @@ export class Viewer extends ViewerBase{
         boundPlane.expandByPoint(this.bound.boundingBox.max.clone().setZ(this.bound.center.z))//最高高度为bound的中心高度
         FirstPersonControls.boundPlane = boundPlane
         FirstPersonControls.standardSpeed = THREE.Math.clamp( Math.sqrt(this.bound.boundSize.length() )/ 100 ,   0.02,0.5); //在这个boundPlane中的速度
-          
+        
+
+        viewer.scene.pointclouds.forEach(e=>{//海拔范围
+            e.material.heightMin = this.bound.boundingBox.min.z
+            e.material.heightMax = this.bound.boundingBox.max.z
+        })
+        
     }
     
     waitForLoad(object, isLoadedCallback){//等待加载时显示loading。主要是贴图