Jelajahi Sumber

fix: 导航

xzw 3 tahun lalu
induk
melakukan
79b8ebd5e5

+ 2 - 2
examples/4dkk.html

@@ -33,7 +33,7 @@
 	
 	<div class="potree_container" style="position: absolute; width: 100%; height: 100%; left: 0px; top: 0px; ">
 		<div id="potree_render_area" style="background-image: url('../../build/potree/resources/images/background.jpg');">
-		
+            
 		</div>
 		<div id="potree_sidebar_container"> </div>
 	</div>
@@ -53,7 +53,7 @@
         
         var number = browser.urlHasValue('m',true);
         console.log(number)
-        Potree.start(document.getElementById("potree_render_area"), number);
+        Potree.start(document.getElementById("potree_render_area"),null, number);
         
           
 		/*

+ 8 - 9
libs/three.js/lines/LineMaterial.js

@@ -352,18 +352,17 @@ var LineMaterial = function ( parameters ) {
         if(e.viewport.name != 'mapViewport') this.updateDepthParams(e) 
     })   
 
-    let setSize = (e)=>{
-        let viewportOffset = e.viewportOffset || new THREE.Vector2()
-        this.uniforms.resolution.value.set(e.resolution.x, e.resolution.y);
-        this.uniforms.viewportOffset.value.set(viewportOffset.x, viewportOffset.y);
+    let setSize = (e)=>{ 
+        let viewportOffset = new Vector2(e.left||0, e.bottom||0) 
+        this.uniforms.resolution.value.copy(e.resolution)
+        this.uniforms.viewportOffset.value.copy(viewportOffset)
     }
     
     let viewport = viewer.mainViewport;
-    let viewportOffset = new Vector2(viewport.left, viewport.bottom) 
-    let resolution = viewport.resolution  
-    setSize({viewportOffset, resolution} )
-    
-    
+     
+    setSize(viewport)
+
+
     viewer.addEventListener('resize',(e)=>{
         //if(!e.viewport || e.viewport.name != 'mapViewport'){
             setSize(e)

+ 9 - 1
note.txt

@@ -6,10 +6,12 @@ npm start
 
 应用navvis : 
  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://120.25.146.52:9294/indoor/{sceneCode}/api/initRecount
 
-http://indoor.popsmart.cn:8094/zdoblh-yz/
+
+
 用户名:admin
 密码:ipadmin
 
@@ -24,6 +26,12 @@ t-ia44BhY 机场(两个数据集。点量大 )
 t-iksBApb 一楼 一个数据集 十个点左右
 t-Zvd3w0m 室内 4dkk的场景 三个点
 t-CwfhfqJ 大佛 有平面图
+t-OW5ShsQ 一楼 有平面图 点五个
+
+------------
+本地测试
+t-bnC8jkv
+t-20211031
 =============================
 地图lib:ol  全局变量    viewer.mapView
 

+ 33 - 10
src/PointCloudOctree.js

@@ -162,8 +162,8 @@ export class PointCloudOctree extends PointCloudTree {
 		this.profileRequests = [];
 		this.name = '';
 		this._visible = true;
-        this.isVisible = true//add
-        
+        //this._isVisible = true//add
+        this.unvisibleReasons = []
         
 		{
 			let box = [this.pcoGeometry.tightBoundingBox, this.getBoundingBoxWorld()]
@@ -1143,22 +1143,45 @@ export class PointCloudOctree extends PointCloudTree {
 		return this._visible;
 	}
 
-	set visible(value){
-
+	set visible(value){ 
 		if(value !== this._visible){
-			this._visible = value;
-
+			this._visible = value; 
 			this.dispatchEvent({type: 'visibility_changed', pointcloud: this});
 		}
 
 	}
+    
+    updateVisible(reason, ifShow){//当所有加入的条件都不为false时才显示
+        if(ifShow){
+            var index = this.unvisibleReasons.indexOf(reason);
+            index > -1 && this.unvisibleReasons.splice(index, 1);
+            if(this.unvisibleReasons.length == 0)this.visible = true;
+        }else {
+            if(!this.unvisibleReasons.includes(reason)) this.unvisibleReasons.push(reason);
+            this.visible = false;    
+        }
+        
+    }
+    
+    getVisible(reason){//获取在某条件下是否可见.  注: 用户在数据集选择可不可见为"datasetSelection"
+        if(this.visible)return true
+        else{
+            return !this.unvisibleReasons.includes(reason)  
+        }
+    }
+    
+    
     /* get isVisible(){//add 手动在数据集选择是否显示(和是否全景图、隐藏点云无关)
-        return this._visible 
+        return this._isVisible 
     }
     set isVisible(visi){
-        this._visible = visi
-        //this.visible = 
-    } */
+        
+        if(!visi)this.visible = false
+        
+    
+    
+        this._isVisible = visi
+    }  */
 }
 
 

+ 2 - 1
src/Potree.js

@@ -174,7 +174,8 @@ export async function loadDatasets(callback){//之后直接把path写进来
 export async function loadMapEntity(callback){
     var path 
     if(Potree.fileServer){
-        path = `/laser/tiledMap/${Potree.settings.number}/tiledMap` 
+        if(!Potree.settings.floorplanType)return /* 等待平面图类型定义好会加载 */
+        path = `/laser/tiledMap/${Potree.settings.number}/tiledMap/${Potree.settings.floorplanType}` 
     }else{
         path = `https://${Potree.config.urls.prefix2}/indoor/${Potree.settings.number}/api/tiled_maps`
         

+ 2 - 2
src/Potree_update_visibility.js

@@ -76,7 +76,7 @@ export function updateVisibilityStructures(pointclouds, camera, areaSize) {
 		let camObjPos = new THREE.Vector3().setFromMatrixPosition(camMatrixObject);
 		camObjPositions.push(camObjPos);
 
-		if ( pointcloud.isVisible &&  pointcloud.root !== null) {//改 visible -> isVisible
+		if ( pointcloud.getVisible('datasetSelection') &&  pointcloud.root !== null) {//改 visible -> 
 			priorityQueue.push({pointcloud: i, node: pointcloud.root, weight: Number.MAX_VALUE});
 		}
 
@@ -133,7 +133,7 @@ export function updateVisibility(pointclouds, camera, areaSize){
 	let pointcloudTransformVersion = Potree._pointcloudTransformVersion;
 	for(let pointcloud of pointclouds){
 
-		if(!pointcloud.isVisible){//改 visible -> isVisible
+		if(!pointcloud.getVisible('datasetSelection')){//改 visible ->  
 			continue;
 		}
 

+ 88 - 18
src/modules/Images360/Images360.js

@@ -88,14 +88,18 @@ export class Images360 extends EventDispatcher{
             /* if(currentlyHovered && currentlyHovered.pano){
 				this.focusPano(currentlyHovered.pano);
 			}else{//add */
-                if(this.currentPano){
-                    this.flyToPanoClosestToMouse() 
-                } 
+                if(!Potree.settings.dblToFocusPoint || this.currentPano){//双击不会focus点云 或者 已经focusPano了
+                    this.flyToPanoClosestToMouse()   
+                }
+                
+                  
             //}  
         })
         
         viewer.addEventListener("global_mousemove", (e) => { 
-            e.intersectPoint && this.updateClosestPano(e.intersectPoint)
+            if(Potree.settings.ifShowMarker && e.hoverViewport == viewer.mainViewport){//如果不显示marker,就在点击时再更新
+                this.updateClosestPano(e.intersectPoint)
+            }
 		});
 
         if(!Potree.settings.isOfficial){
@@ -280,7 +284,7 @@ export class Images360 extends EventDispatcher{
                     if(show != ifShowMarker){
                         this.panos.forEach(pano=>{
                             pano.marker.visible = show
-                            pano.mesh.visible = show
+                            Potree.settings.showPanoMesh && (pano.mesh.visible = show)
                             //pano.mesh.label && (pano.mesh.label
                         })
                         this.emit('markersDisplayChange', show) 
@@ -447,9 +451,10 @@ export class Images360 extends EventDispatcher{
         
         var pano = toPano.pano 
         
-        var duration = toPano.duration || Potree.config.transitionsTime.panoToPano 
         
-        //console.log("flyto "+pano.file.split('/').pop()  )     
+        var duration = toPano.duration || 300+Math.min(Potree.config.transitionsTime.flySpeed * this.position.distanceTo(pano.position),  Potree.config.transitionsTime.panoToPano )  
+        
+        //console.log("flyto "+pano.id + ' duration: ' + duration )     
         
         this.nextPano = pano
         //不飞的话是否不要执行这段?
@@ -644,7 +649,62 @@ export class Images360 extends EventDispatcher{
 		this.elUnfocus && (this.elUnfocus[0].style.display = "none");
 	}
 
-	load(pano, ){ 
+
+
+
+
+
+    /* bump(direction) {//撞墙弹回效果
+        if (!this.flying) {
+            var t, i, n, r = settings.transition,
+                o = (r.flytimeMaxDistanceThreshold * r.flytimeDistanceMultiplier + r.flyTime) / 10,
+                a = this.camera.getWorldDirection().dot(direction),
+                s = Math.abs(a) > .5;
+            if (s)
+                t = function() {
+                    transitions.start(lerp.property(this.cameraControls.cameras[ViewMode.PANORAMA], "zoom", a > 0 ? 1.04 : .96), o, i, 0, easing.easeInOutSine, "bumpZStart")
+                }
+                .bind(this),
+                i = function() {
+                    transitions.start(lerp.property(this.cameraControls.cameras[ViewMode.PANORAMA], "zoom", 1), 3 * o, n, 0, easing.easeInOutSine, "bumpZRelax")
+                }
+                .bind(this);
+            else {
+                var l = this.camera.position.clone(),
+                    c = direction.clone();
+                this.raycaster.set(l, c);
+                var h = this.model.floors.reduce(function(e, t) {
+                        return e.concat(t.collider.children)
+                    }, []),
+                    d = this.raycaster.intersectObjects(h),
+                    p = d.length > 0 ? d[0].distance / 25 : .04,
+                    g = l.clone().add(c.multiplyScalar(p));
+                t = function() {
+                        transitions.start(lerp.vector(this.cameraControls.cameras[ViewMode.PANORAMA].position, g), o, i, 0, easing.easeInOutSine, "bumpTStart")
+                    }
+                    .bind(this),
+                    i = function() {
+                        transitions.start(lerp.vector(this.cameraControls.cameras[ViewMode.PANORAMA].position, l), 5 * o, n, 0, easing.easeInOutSine, "bumpTRelax")
+                    }
+                    .bind(this)
+            }
+            
+            
+            n = (){
+                this.mode == "panorama" && (this.flying = !1)  //改
+            }
+            
+            this.flying = !0,
+            t()
+        }
+    };
+ */
+
+
+
+
+
+	/* load(pano, ){ 
 		return new Promise(resolve => {
 			let texture = texLoader.load(pano.file, resolve);
 			texture.wrapS = THREE.RepeatWrapping;
@@ -659,7 +719,7 @@ export class Images360 extends EventDispatcher{
             texture.generateMipmaps = true;  
             
 		}); 
-	}
+	} */
 
 
 
@@ -668,6 +728,12 @@ export class Images360 extends EventDispatcher{
             //this.intersect = this.getMouseIntersect();
             this.intersect && this.updateClosestPano(this.intersect);
         } */
+         
+        if(!Potree.settings.ifShowMarker){//不显示marker的时候mousemove没更新鼠标最近点所以更新
+            this.updateClosestPano(viewer.inputHandler.intersectPoint)
+        }
+        
+        
         if (this.closestPano) {
             return this.flyToPano({
                 pano: this.closestPano
@@ -721,16 +787,20 @@ export class Images360 extends EventDispatcher{
 		
     }
 
-    updateClosestPano(intersect) {
-        intersect = intersect && (intersect.location || intersect)
+    updateClosestPano(intersect) {//距离reticule最近的点  可以是null
+    
+        intersect = intersect && intersect.location
+        if(!intersect)return
+        //intersect = intersect && (intersect.location || intersect)
+        
         var filterFuncs = [];
         //if (this.mode === ViewMode.PANORAMA) {
-            if (!this.currentPano) {
+            /* if (!Potree.settings.isOfficial && !this.currentPano) {
                 return;
-            }
-            
+            } */
+        if(this.isAtPano() ){ 
             filterFuncs.push(Images360.filters.not(this.currentPano));
- 			filterFuncs.push(Images360.filters.inFloorDirection(this.currentPano, viewer.scene.view.direction, .25)),//许钟文改
+ 			filterFuncs.push(Images360.filters.inFloorDirection(this.position, viewer.scene.view.direction, .25)),//许钟文改
 			//filterFuncs.push(Images360.filters.isNeighbourPanoTo(this.currentPano));
             filterFuncs.push(Images360.filters.isCloseEnoughTo(intersect, 0.35));
        /*  } else {
@@ -740,7 +810,7 @@ export class Images360 extends EventDispatcher{
             objects.record.control.isRecording || filterFuncs.push(Panorama.filters.isOnVisibleFloor());
             this.mode !== ViewMode.FLOORPLAN && filterFuncs.push(Panorama.filters.inDirection(this.position, this.getDirection(), .25));
         } */
-         
+        }
         
         var pano = Common.find(this.panos,  filterFuncs, [Images360.sortFunctions.floorDistanceToPoint(intersect)]);
         if (pano != this.closestPano) {
@@ -1016,9 +1086,9 @@ Images360.filters = {
 			return r.dot(t.clone().setZ(0).normalize()) > i || o.dot(t) > i
         }
     },
-    inFloorDirection: function(t, e, o) {//许钟文 改 for鱼眼
+    inFloorDirection: function(pos, e, o) {//许钟文 改 for鱼眼
 		return function(n) {
-			var i = n.floorPosition.clone().sub(t.floorPosition).setZ(0).normalize();//改成在xz方向上,否则点击墙面不会移动
+			var i = n.floorPosition.clone().sub(pos).setZ(0).normalize();//改成在xz方向上,否则点击墙面不会移动
 			return i.dot(e) > o
 		}
 	}, 

+ 5 - 3
src/modules/Images360/Panorama.js

@@ -17,7 +17,9 @@ const labelProp = {
 let standardMarkerMat 
 let getMarerMat = function(){
     if(!standardMarkerMat) {
-        standardMarkerMat = new THREE.MeshBasicMaterial({opacity:0.5, side: THREE.DoubleSide , map:texLoader.load( Potree.resourcePath+'/textures/marker.png' ) ,transparent:true})
+        let map = texLoader.load( Potree.resourcePath+'/textures/marker.png' )
+        map.anisotropy = 4 // 各向异性过滤 .防止倾斜模糊
+        standardMarkerMat = new THREE.MeshBasicMaterial({opacity:0.5, side: THREE.DoubleSide , map ,transparent:true})
     }
     return standardMarkerMat.clone()
 }
@@ -174,7 +176,7 @@ class Panorama extends EventDispatcher{
             //this.quaternion = quaternion
         } 
         this.mesh = mesh;
-         
+        if(!Potree.settings.showPanoMesh) mesh.visible = false
          
         let marker = new THREE.Mesh(planeGeo, getMarerMat() ) 
             marker.up.set(0,0,1)
@@ -210,7 +212,7 @@ class Panorama extends EventDispatcher{
         this.floorPosition = floorPosition
         this.mesh.position.copy(this.position)
         this.marker.position.copy(this.floorPosition) 
-        //this.marker.position.z+=0.1
+        this.marker.position.z+=0.1//会被点云遮住
         this.label && (this.label.position.copy(this.floorPosition), this.label.position.z+=0.2)
     }
     

+ 18 - 11
src/navigation/FirstPersonControls.js

@@ -20,6 +20,8 @@ import {EventDispatcher} from "../EventDispatcher.js";
 import cameraLight from "../utils/cameraLight.js";
 
 
+ 
+
 export class FirstPersonControls extends EventDispatcher {
 	constructor (viewer, viewport) {
 		super();
@@ -221,13 +223,17 @@ export class FirstPersonControls extends EventDispatcher {
                 } else if (e.delta > 0) {
                     ratio = 1.1
                 } 
-                /* camera.left *= ratio;
-                camera.right *= ratio
-                camera.top *= ratio
-                camera.bottom *= ratio */
-                camera.zoom *= ratio
+                let zoom = camera.zoom * ratio
+                let limit = Potree.config.OrthoCameraLimit.zoom
+                zoom = THREE.Math.clamp(zoom, limit.min,limit.max )
+                
+                if(camera.zoom != zoom){
+                    console.log('zoom')
+                    camera.zoom = zoom
+                    camera.updateProjectionMatrix()
+                }
+                
                 
-                camera.updateProjectionMatrix()
                 
             }else{
                 var direction = this.currentViewport.view.direction.clone();
@@ -243,8 +249,11 @@ export class FirstPersonControls extends EventDispatcher {
             
 		};
 
-		let dblclick = (e) => {
+		let dblclick = (e) => { 
             if(!this.enabled)return
+            
+            if(!Potree.settings.dblToFocusPoint)return;//调试时才可双击
+            
             if(Potree.settings.displayMode == 'showPointCloud'/* !viewer.images360.isAtPano() */) this.zoomToLocation(e.mouse);
 		};
 
@@ -535,11 +544,9 @@ export class FirstPersonControls extends EventDispatcher {
             
             
 		}
+ 
 
-
-        
-
-		 { // decelerate over time
+        { // decelerate over time
 			let attenuation = Math.max(0, 1 - this.fadeFactor * delta);
 			/* this.yawDelta *= attenuation;
 			this.pitchDelta *= attenuation; 

+ 4 - 2
src/navigation/InputHandler.js

@@ -68,8 +68,10 @@ export class InputHandler extends EventDispatcher {
         
 		this.domElement.addEventListener('mousewheel', this.onMouseWheel.bind(this), false);
 		this.domElement.addEventListener('DOMMouseScroll', this.onMouseWheel.bind(this), false); // Firefox
-		this.domElement.addEventListener('dblclick', this.onDoubleClick.bind(this));
-		this.domElement.addEventListener('keydown', this.onKeyDown.bind(this));
+        
+		this.domElement.addEventListener('dblclick', this.onDoubleClick.bind(this)); 
+		
+        this.domElement.addEventListener('keydown', this.onKeyDown.bind(this));
 		this.domElement.addEventListener('keyup', this.onKeyUp.bind(this));
 		this.domElement.addEventListener('touchstart', this.onTouchStart.bind(this));
 		this.domElement.addEventListener('touchend', this.onTouchEnd.bind(this));

+ 346 - 0
src/navigation/RouteGuider.js

@@ -0,0 +1,346 @@
+
+import * as THREE from "../../libs/three.js/build/three.module.js";
+import {Utils} from "../utils.js";
+import { EventDispatcher } from "../EventDispatcher.js";
+import Sprite from '../viewer/Sprite'
+
+
+const texLoader = new THREE.TextureLoader()
+const arrowSpacing = 1 //间隔
+const arrowSize = arrowSpacing * 0.5
+const planeGeo = new THREE.PlaneBufferGeometry(1,1);
+
+const sphereSizeInfo = {
+      nearBound : 2, scale:arrowSize, restricMeshScale : true,
+}
+
+
+export class RouteGuider extends EventDispatcher{
+    constructor () {
+		super();
+        this._routeStart = null
+        this._routeEnd = null
+        this.route = [];
+        this.curve = []
+        this.sceneMeshGroup = new THREE.Object3D;
+        this.mapMeshGroup = new THREE.Object3D;
+        
+        viewer.addEventListener('loadPointCloudDone',this.init.bind(this))
+        
+    
+    }
+    init(){
+        if(this.inited) return;
+        
+        var polesMats = {
+            shadowMat: new THREE.MeshBasicMaterial({ 
+                transparent:true, depthTest:false,
+                map: texLoader.load(Potree.resourcePath+'/textures/pano_instruction_bottomMarker.png' )  
+            }),
+            sphereMat : new THREE.MeshBasicMaterial({
+                transparent:true, depthTest:false,
+                map: texLoader.load(Potree.resourcePath+'/textures/whiteCircle.png' )  
+            }), 
+            hatMats:{
+                start:  new THREE.MeshBasicMaterial({
+                    transparent:true, depthTest:false,
+                    map: texLoader.load(Potree.resourcePath+'/textures/pano_instruction_start_route.png' )  
+                }),
+                end:  new THREE.MeshBasicMaterial({
+                    transparent:true, depthTest:false,
+                    map: texLoader.load(Potree.resourcePath+'/textures/pano_instruction_target_reached.png' )  
+                }) 
+            }
+        }
+         
+        this.poleStart = this.createPole(polesMats, 'start') 
+        this.poleEnd = this.createPole(polesMats, 'end') 
+        
+        this.sceneMeshGroup.add(this.poleStart)
+        this.sceneMeshGroup.add(this.poleEnd)
+        
+        
+        let map = texLoader.load(Potree.resourcePath+'/textures/routePoint_panorama.png' )  
+        map.anisotropy = 4 // 各向异性过滤 .防止倾斜模糊 
+        this.arrow = new THREE.Mesh(planeGeo, new THREE.MeshBasicMaterial({
+            transparent:true,
+            depthTest:false, 
+            map
+        }))
+        this.arrow.scale.set(arrowSize,arrowSize,arrowSize)
+        viewer.setObjectLayers(this.arrow, 'route' )
+         
+        
+        this.testArrow = this.arrow.clone();
+        this.testArrow.material = this.arrow.material.clone()
+        this.testArrow.material.color = 'red'
+        
+        this.arrows = new THREE.Object3D;
+        this.sceneMeshGroup.add(this.arrows)
+        
+        viewer.setObjectLayers(this.sceneMeshGroup, 'route' )
+        //this.sceneMeshGroup.traverse(e=>e.renderOrder = 90)
+        
+        
+        viewer.scene.scene.add(this.sceneMeshGroup);
+        this.sceneMeshGroup.visible = /* this.poleStart.visibile = this.poleEnd.visibile = */ false
+       
+        //-------------map---------------------
+        
+        this.mapMarkStart = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
+            transparent:true, depthTest:false,
+            map: texLoader.load(Potree.resourcePath+'/textures/map_instruction_start_route.png' )  
+        }))
+        this.mapMarkEnd = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
+            transparent:true, depthTest:false,
+            map: texLoader.load(Potree.resourcePath+'/textures/map_instruction_target_reached.png' )  
+        }))
+        
+        
+        this.mapArrow = new THREE.Mesh( planeGeo, new THREE.MeshBasicMaterial({
+            transparent:true, depthTest:false,
+            map: texLoader.load(Potree.resourcePath+'/textures/routePoint_map_fsna.png' )  
+        }))
+        this.mapArrow.scale.set(arrowSize,arrowSize,arrowSize)
+        this.mapArrows = new THREE.Object3D;
+        this.mapArrows.name = 'mapArrows'
+        //viewer.setObjectLayers(this.mapArrow, 'route' )
+        
+        
+        
+        
+        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
+        
+        viewer.mapViewer.emit('add',{object:this.mapMeshGroup, name:'route'})
+        this.mapArrow.layers.mask = this.mapArrows.layers.mask // 修改成和map中的layer一样的
+        
+        this.inited = true
+    }
+    
+    
+    createPole(polesMats, name){
+        const height = 1.5, sphereCount = 6, shadowSize = sphereSizeInfo.scale,  sphereSize = 0.04
+        
+        var group = new THREE.Object3D;
+            group.name = 'pole_'+name
+        var shadow = new THREE.Mesh(planeGeo,polesMats.shadowMat)
+        shadow.scale.set(shadowSize,shadowSize,shadowSize)
+        var sliceDis = height / (sphereCount+1);
+        group.add(shadow) 
+         
+        for(let i=0;i<sphereCount;i++){
+            var sphere = new Sprite({mat: polesMats.sphereMat}) 
+            sphere.position.set(0,0,sliceDis*(i+1))
+            sphere.scale.set(sphereSize,sphereSize,sphereSize);
+            group.add(sphere)
+        }
+        
+        var hatSphere = new Sprite({mat: polesMats.hatMats[name], sizeInfo:sphereSizeInfo}) 
+        hatSphere.position.set(0,0,height)
+        hatSphere.scale.copy(shadow.scale)
+        group.add(hatSphere)
+        return group
+    }
+    
+    
+    addTestArrow(){
+        
+    }
+    
+    addArrow(position){ 
+        var arrow = this.arrow.clone()
+        arrow.position.copy(position); 
+        this.arrows.add(arrow); 
+    }
+    addMapArrow(position){ 
+        var mapArrow = this.mapArrow.clone()
+        mapArrow.position.copy(position).setZ(0) 
+        this.mapArrows.add(mapArrow);
+    }
+    
+    
+    setArrowDir(arrows,index){
+        let arrow = arrows[index]
+        var nextOne = arrows[index+1];
+        var nextPos = nextOne ? nextOne.position : this.routeEnd
+        var direction = new THREE.Vector3().subVectors(arrow.position, nextPos).setZ(0);
+        //direction.normalize();
+        //console.log(direction.toArray())
+        var angle = Math.atan2(direction.y, direction.x ) + Math.PI/2 //Math.PI/2是因为贴图本身箭头方向不朝x
+        arrow.rotation.z = angle
+        //console.log(angle)
+    }
+    
+    
+    get routeStart(){
+        return this._routeStart && this._routeStart.clone()
+    }
+    
+    set routeStart(pos){
+        this._routeStart = pos && pos.clone()
+        this.generateRoute()
+    }
+    
+    get routeEnd(){
+        return this._routeEnd && this._routeEnd.clone() 
+    }
+    
+    set routeEnd(pos){
+        this._routeEnd = pos && pos.clone()
+        this.generateRoute()
+    }
+    
+    
+    
+    
+    generateRoute(){
+        if(!this.routeStart || !this.routeEnd)return
+        this.clearRoute()
+        
+        //array.reduce(function(total, currentValue, currentIndex, arr), initialValue)
+        
+        
+        let create = ()=>{ 
+            this.routeLenth = this.route.reduce((total, currentValue, currentIndex, arr)=>{
+                if(currentIndex == 0)return 0
+                return total + currentValue.distanceTo(arr[currentIndex-1]);
+            },0)
+            let count = Math.max(2,Math.round(this.routeLenth / arrowSpacing))//点数
+            
+            const curve = new THREE.CatmullRomCurve3( this.route ); 
+            curve.curveType = 'catmullrom'
+            this.curve = curve
+            
+            const scenePoints = curve.getSpacedPoints( count );//更平均
+            //const scenePoints = curve.getPoints( count );
+            scenePoints.splice(0,1);//去掉首尾
+            scenePoints.pop()
+            this.scenePoints = scenePoints
+            
+            this.updateMapArrows()
+            
+            
+            
+            this.displayRoute()
+        }
+        
+        
+        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.forEach(item=>{
+                    let pos = viewer.transform.lonlatToLocal.forward(item.location)
+                    pos = new THREE.Vector3().fromArray(pos)
+                    this.route.push(pos)
+                })
+                
+                create()
+               /*
+                distance: 0.17581000000000116
+                distance_to_previous: 0.17581000000000116
+                id: 567
+                instruction: {type: 'source_projection_to_navgraph'}
+                latitude: 22.366605927999238
+                location: (3) [113.5957510575092, 22.366605927999238, -1.12419]
+                longitude: 113.5957510575092
+                z: -1.12419
+                             */
+                
+            })
+            
+            
+        }else{
+            //创个直线
+            /* const sliceDis = 1
+            let dis = this.routeStart.distanceTo(this.routeEnd);
+            let count = Math.max(2,Math.round(dis / sliceDis))//点数
+            let realSlideDis = dis / (count-1);
+            let dir = new THREE.Vector3().subVectors(this.routeEnd, this.routeStart).normalize().multiplyScalar(realSlideDis);
+            this.route = [this.routeStart];
+            for(let i=0;i<count-1;i++){
+                let lastOne = this.route[i];
+                this.route.push(new THREE.Vector3().addVectors(lastOne,dir))
+            }
+            this.route.splice(0,1) //route不用包含收尾 */
+            this.route = [this.routeStart, this.routeEnd]
+            create()
+            
+        }
+          
+    }
+    
+    updateMapArrows(){
+          
+        let count = Math.max(2,Math.round(this.routeLenth / viewer.mapViewer.camera.zoom *10/ arrowSpacing))//点数
+        const mapPoints = this.curve.getSpacedPoints( count ); 
+        mapPoints.splice(0,1);//去掉首尾
+        mapPoints.pop()
+        
+        this.mapPoints = mapPoints
+    }
+    
+    
+    
+    displayRoute(){
+        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.scenePoints.forEach(e=>this.addArrow(e))
+        this.mapPoints.forEach(e=>this.addMapArrow(e))
+        this.arrows.children.forEach((e,i)=>this.setArrowDir(this.arrows.children,i));
+        this.mapArrows.children.forEach((e,i)=>this.setArrowDir(this.mapArrows.children,i));
+    }
+    
+    clearRoute(){
+        this.routeLenth = 0
+        this.route = []
+        this.scenePoints = []
+        this.mapPoints = []
+        
+        let arrows = this.arrows.children.slice(0)
+        let mapArrows = this.mapArrows.children.slice(0)
+        arrows.forEach(e=>{
+            this.arrows.remove(e)
+        })
+        mapArrows.forEach(e=>{
+            this.mapArrows.remove(e)
+        })
+    }
+    
+    clear(){//退出
+        this.sceneMeshGroup.visible = false 
+        this.mapMeshGroup.visible = false
+        this.routeStart = null
+        this.routeEnd = null
+        this.clearRoute()
+        
+    }
+}

+ 32 - 30
src/settings.js

@@ -71,7 +71,8 @@ const config = {//配置参数   不可修改
     },
      
     transitionsTime:{
-        panoToPano: 1500,
+        flySpeed : 400, // 毫秒/米
+        panoToPano: 2000,
         flyIn:1000,
         flyOut:1000,
     }
@@ -95,6 +96,15 @@ const config = {//配置参数   不可修改
         }
         //minNodeSize?
     },
+    
+    
+    
+    
+    
+    
+    
+    
+    
     measure:{
         lineColor:"#00c7b2",
         highLightColor:'#FFFFFF',//'#02e4cc', //hover时线条和mainLabel颜色
@@ -126,7 +136,7 @@ const config = {//配置参数   不可修改
         magnifier:5, 
         volume:6,
         transformationTool:7,
-        
+        route:10,
         map:8,
         mapObjects:9,
     },
@@ -156,34 +166,15 @@ const config = {//配置参数   不可修改
         distanceFactor: -1,
         optionalityFactor: 3
     },
+    OrthoCameraLimit:{
+        zoom:{min:0.001, max:100}, //如果camera缩太小,地图会因为数字边界问题而扭曲
+        posBound:{ 
+            min: {x:-1e5, y:-1e5,z:-1 / 0},
+            max: {x:1e5, y:1e5, z:1 / 0  }
+        }
+    }
+    ,
     
-    
-    signedUrlDefaultExpireTime: 24e4,
-    signedUrlCheckInterval: 1e4,
-    signedUrlRefreshBuffer: 15e3,
-    dollhouseFOV: 70,
-    dollhouseNear: 1,
-    dollhouseFar: 5e3,
-    insideFOV: 70,
-    insideFOVMax: 120,
-    insideNear: .1,
-    insideFar: 5e3,
-    insideLookSpeed: .12,
-    insideLookLimitUp: 40,
-    insideLookLimitDown: -90,//-40,
-    orthoNear: 1,
-    orthoFar: 5e3,
-    orthoBase: 10,
-    narrowLandscapeHeight: 290,
-    reallyNarrowLandscapeHeight: 250,
-    visionTilingStartDate: new Date("8/26/2016"),
-    visionTilingStartVersion: "1.1.407.13667",
-    windowHeightHighQualityThreshold: 900,
-    tourStepDelayDefault: 3500,
-    tourStepDelaySlideShow: 5e3,
-    workshopApsect: 9 / 16,
-    highQualityMaxZoom: 2,
-    ultraHighQualityMaxZoom: 3
 }
 /* 显示模式:
 
@@ -200,13 +191,24 @@ function getPrefix(){
 
 let settings = {//设置   可修改
     number: '', //场景序号
+    isOfficial:false,
     displayMode:'',
     isTest :browser.urlHasValue('test'),
     prefix:getPrefix(),
     pointDensity: '',
     ifShowMarker:true,//显示漫游点
+    floorplanType:null,//平面图类型 'default' | 'diy'
+    cameraFar : 300, //相机最远范围 1-300
+    limitFar: true, //是否使用setting的cameraFar来限制(如在点云裁剪时为false)
+    showPanoMesh:false, //显示小球,
+    dblToFocusPoint:false,//调试时如果需要双击飞向某个点云的点,就打开。此时不在漫游点的话单击将无法漫游。//因和单击漫游冲突 
+    
+    
 }
-settings.isLocalhost = settings.prefix.includes('localhost')
 
 
+
+settings.isLocalhost = settings.prefix.includes('localhost')
+ 
+
 export {config, settings}

+ 8 - 0
src/utils/Common.js

@@ -76,6 +76,14 @@ var Common = {
         return set;
     }
     ,
+    
+    
+    CloneJson : function(data){
+        var str = JSON.stringify(data)
+        return JSON.parse(str)
+    }
+    
+    ,
      
     CloneObject : function(copyObj, result, isSimpleCopy, extraReplace) {
         //isSimpleCopy 只复制最外层

+ 6 - 2
src/utils/Measure.js

@@ -46,14 +46,14 @@ export class Measure extends THREE.Object3D {
 	constructor (prop) {
 		super();
 		this.constructor.counter = (this.constructor.counter === undefined) ? 0 : this.constructor.counter + 1;
-		this.name = 'Measure_' + this.constructor.counter;
+		
 		this.maxMarkers = Number.MAX_SAFE_INTEGER;
         
         this.transformData(prop);
         for(let i in prop){
             this[i] = prop[i]
         }
-        
+        this.name = this.measureType + this.constructor.counter  //'Measure_' + this.constructor.counter;
         
 		this.points = [];
 		this._showDistances = true;
@@ -399,6 +399,9 @@ export class Measure extends THREE.Object3D {
                 edgeLabel.addEventListener('mouseleave',()=>{
                     this.setSelected(false, 'edgeLabel')
                 })  
+                edgeLabel.addEventListener('click',()=>{
+                    viewer.focusOnObject(this, 'measure')
+                })
             }
              
             viewer.setObjectLayers(edgeLabel, 'measure' )
@@ -1151,6 +1154,7 @@ export class Measure extends THREE.Object3D {
 
 
     setUnitSystem(unitSystem){
+        console.log(this.name +':' +this.unitSystem)
         if(unitSystem != this.unitSystem){
             if(unitSystem == "metric"){
                 

+ 3 - 3
src/viewer/EDLRenderer.js

@@ -183,13 +183,13 @@ export class EDLRenderer{//Eye-Dome Lighting 眼罩照明
         //viewer.dispatchEvent({type: "render.pass.begin",viewer: viewer});
 	
 		                                           
-		const visiblePointClouds = viewer.scene.pointclouds.filter(pc =>  pc.visible );
-		const visiblePointClouds2 = viewer.scene.pointclouds.filter(pc => pc.isVisible  );
+		//const visiblePointClouds = viewer.scene.pointclouds.filter(pc =>  pc.visible );
+		const visiblePointClouds2 = viewer.scene.pointclouds.filter(pc => pc.getVisible('datasetSelection')  ); 
 		const showPointClouds = viewer.scene.pointclouds.some(e=>e.visible)
          
         viewer.scene.pointclouds.forEach(e=>{//为了绘制到depthTexture,先显示(展示全景图时隐藏了点云,所以需要显示下。且放大镜需要绘制点云)
             e.oldVisi = e.visible
-            if(e.isVisible)e.visible = true; 
+            if(e.getVisible('datasetSelection') )e.visible = true; 
         }) 
         
         

+ 12 - 1
src/viewer/View.js

@@ -136,12 +136,14 @@ export class View{
 			.add(up.multiplyScalar(z));
 
 		this.position = this.position.add(t);
+        this.restrictPos()
 	}
 
 	translateWorld (x, y, z) {
 		this.position.x += x;
 		this.position.y += y;
 		this.position.z += z;
+        this.restrictPos()
 	}
 
 	/* setView(position, target, duration = 0, callback = null, onUpdate = null, Easing=''){
@@ -232,6 +234,7 @@ export class View{
 
 		if(duration === 0){
 			this.position.copy(endPosition);
+            this.restrictPos()
 			endTarget && this.lookAt(endTarget);
             onUpdate && onUpdate(1)
             callback && callback()
@@ -250,7 +253,7 @@ export class View{
 
                     this.lookAt(target);
                 }
-
+                this.restrictPos()
  
 
                 onUpdate && onUpdate(t)//add
@@ -261,6 +264,14 @@ export class View{
 
     }
 
+    restrictPos(){//add
+        if(this.limitBound){
+            this.position.clamp(this.limitBound.min, this.limitBound.max)
+        }
+    }
+
+
+
     setCubeView(dir) {
 		 
 		switch(dir) {

+ 276 - 285
src/viewer/viewer.js

@@ -51,28 +51,30 @@ import cameraLight from "../utils/cameraLight.js";
 import math from "../utils/math.js";
  
 import {UoMService}  from '../utils/UnitConvert'
- 
- 
+import {RouteGuider}  from '../navigation/RouteGuider'
+
+let mapArea; 
 
 export class Viewer extends ViewerBase{
 	
-	constructor(domElement, args = {}){
+	constructor(domElement, mapArea_, args = {}){
 		super(domElement,args);
         window.viewer = this
         this.modules = { //add
             Clip : Clip,
-            Alignment : Alignment
-            
+            Alignment : Alignment,
+            RouteGuider : new RouteGuider
         }
         
         
         
         //add --------
+        
         this.navigateMode = 'free' // 'panorama'; 'free'自由模式是只显示点云或者未进入到漫游点, 
         this.isEdit = true
         CursorDeal.attachToViewer(this)//ADD
         this.unitConvert = new UoMService();
-       
+        mapArea = mapArea_
 		//-------------
         
         
@@ -89,82 +91,58 @@ export class Viewer extends ViewerBase{
 		</div>`);
 		$(domElement).append(this.elMessages);
 		
-		try{
-
-		{ // generate missing dom hierarchy
-			if ($(domElement).find('#potree_map').length === 0) {
-				let potreeMap = $(`
-					<div id="potree_map" class="mapBox" style="position: absolute; left: 50px; top: 50px; width: 400px; height: 400px; display: none">
-						<div id="potree_map_header" style="position: absolute; width: 100%; height: 25px; top: 0px; background-color: rgba(0,0,0,0.5); z-index: 1000; border-top-left-radius: 3px; border-top-right-radius: 3px;">
-						</div>
-						<div id="potree_map_content" class="map" style="position: absolute; z-index: 100; top: 25px; width: 100%; height: calc(100% - 25px); border: 2px solid rgba(0,0,0,0.5); box-sizing: border-box;"></div>
-					</div>
-				`);
-				$(domElement).append(potreeMap);
-			}
-
-			if ($(domElement).find('#potree_description').length === 0) {
-				let potreeDescription = $(`<div id="potree_description" class="potree_info_text"></div>`);
-				$(domElement).append(potreeDescription);
-			}
-
-			if ($(domElement).find('#potree_annotations').length === 0) {
-				let potreeAnnotationContainer = $(`
-					<div id="potree_annotation_container" 
-						style="position: absolute; z-index: 100000; width: 100%; height: 100%; pointer-events: none;"></div>`);
-				$(domElement).append(potreeAnnotationContainer);
-			}
-
-			if ($(domElement).find('#potree_quick_buttons').length === 0) {
-				let potreeMap = $(`
-					<div id="potree_quick_buttons" class="quick_buttons_container" style="">
-					</div>
-				`);
-
-				// {
-				// 	let imgMenuToggle = document.createElement('img');
-				// 	imgMenuToggle.src = new URL(Potree.resourcePath + '/icons/menu_button.svg').href;
-				// 	imgMenuToggle.onclick = this.toggleSidebar;
-				// 	// imgMenuToggle.classList.add('potree_menu_toggle');
-
-				// 	potreeMap.append(imgMenuToggle);
-				// }
-
-				// {
-				// 	let imgMenuToggle = document.createElement('img');
-				// 	imgMenuToggle.src = new URL(Potree.resourcePath + '/icons/menu_button.svg').href;
-				// 	imgMenuToggle.onclick = this.toggleSidebar;
-				// 	// imgMenuToggle.classList.add('potree_menu_toggle');
-
-				// 	potreeMap.append(imgMenuToggle);
-				// }
-
-				// {
-				// 	let imgMenuToggle = document.createElement('img');
-				// 	imgMenuToggle.src = new URL(Potree.resourcePath + '/icons/menu_button.svg').href;
-				// 	imgMenuToggle.onclick = this.toggleSidebar;
-				// 	// imgMenuToggle.classList.add('potree_menu_toggle');
+        
+            
+        try{
+            
+            if(!Potree.settings.isOfficial)  
+            { // generate missing dom hierarchy
+                if ($(domElement).find('#potree_map').length === 0) {
+                    let potreeMap = $(`
+                        <div id="potree_map" class="mapBox" style="position: absolute; left: 50px; top: 50px; width: 400px; height: 400px; display: none">
+                            <div id="potree_map_header" style="position: absolute; width: 100%; height: 25px; top: 0px; background-color: rgba(0,0,0,0.5); z-index: 1000; border-top-left-radius: 3px; border-top-right-radius: 3px;">
+                            </div>
+                            <div id="potree_map_content" class="map" style="position: absolute; z-index: 100; top: 25px; width: 100%; height: calc(100% - 25px); border: 2px solid rgba(0,0,0,0.5); box-sizing: border-box;"></div>
+                        </div>
+                    `);
+                    $(domElement).append(potreeMap);
+                }
 
-				// 	potreeMap.append(imgMenuToggle);
-				// }
+                if ($(domElement).find('#potree_description').length === 0) {
+                    let potreeDescription = $(`<div id="potree_description" class="potree_info_text"></div>`);
+                    $(domElement).append(potreeDescription);
+                }
 
-				
+                if ($(domElement).find('#potree_annotations').length === 0) {
+                    let potreeAnnotationContainer = $(`
+                        <div id="potree_annotation_container" 
+                            style="position: absolute; z-index: 100000; width: 100%; height: 100%; pointer-events: none;"></div>`);
+                    $(domElement).append(potreeAnnotationContainer);
+                } 
 
-				$(domElement).append(potreeMap);
-			}
-            
-            //add
-            {
-                $(domElement).append($("<div id='potree_labels'></div>"))
-                
-                let mapArea = $("<div id='mapGaode'></div>")
-                $(domElement).append(mapArea)
-                
-                
+                if ($(domElement).find('#potree_quick_buttons').length === 0) {
+                    let potreeMap = $(`
+                        <div id="potree_quick_buttons" class="quick_buttons_container" style="">
+                        </div>
+                    `);
+  
+                    $(domElement).append(potreeMap);
+                }
                 
-            }
+                //add
+                {
+                    
+                    if(!mapArea){
+                        $(domElement).append($("<div id='potree_labels'></div>"))
+                        
+                        mapArea = $("<div id='mapGaode'></div>")
+                        $(domElement).append(mapArea)
+                        mapArea = mapArea[0]
+                    }
+                    
+                }
+                 
              
-            if(!Potree.settings.isOfficial){
                 let domRoot = this.renderer.domElement.parentElement; 
                 let elAttach = $("<input type='button' value='test'></input>");
                 elAttach.css({
@@ -181,245 +159,246 @@ export class Viewer extends ViewerBase{
                 }); 
                 domRoot.appendChild(elAttach[0]);
                 
+                    
+                
                 
             }
             
-		}
-        
-
-        
-		this.pointCloudLoadedCallback = args.onPointCloudLoaded || function () {};
 
-		// if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
-		//	defaultSettings.navigation = "Orbit";
-		// }
+            
+            this.pointCloudLoadedCallback = args.onPointCloudLoaded || function () {};
 
-		this.server = null;
+            // if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) {
+            //	defaultSettings.navigation = "Orbit";
+            // }
 
-		this.fov = 60;
-		this.isFlipYZ = false;
-		this.useDEMCollisions = false;
-		this.generateDEM = false;
-		this.minNodeSize = 30;
-		this.edlStrength = 1.0;
-		this.edlRadius = 1.4;
-		this.edlOpacity = 1.0;
-		this.useEDL = false;
-		this.description = "";
+            this.server = null;
 
-		this.classifications = ClassificationScheme.DEFAULT;
+            this.fov = 60;
+            this.isFlipYZ = false;
+            this.useDEMCollisions = false;
+            this.generateDEM = false;
+            this.minNodeSize = 30;
+            this.edlStrength = 1.0;
+            this.edlRadius = 1.4;
+            this.edlOpacity = 1.0;
+            this.useEDL = false;
+            this.description = "";
 
-		this.moveSpeed = 10;
+            this.classifications = ClassificationScheme.DEFAULT;
 
-		this.lengthUnit = LengthUnits.METER;
-		this.lengthUnitDisplay = LengthUnits.METER;
+            this.moveSpeed = 10;
 
-		this.showBoundingBox = false;
-		this.showAnnotations = true;
-		this.freeze = false;
-		this.clipTask = ClipTask.HIGHLIGHT;
-		this.clipMethod = ClipMethod.INSIDE_ANY;
+            this.lengthUnit = LengthUnits.METER;
+            this.lengthUnitDisplay = LengthUnits.METER;
 
-		this.elevationGradientRepeat = ElevationGradientRepeat.CLAMP;
+            this.showBoundingBox = false;
+            this.showAnnotations = true;
+            this.freeze = false;
+            this.clipTask = ClipTask.HIGHLIGHT;
+            this.clipMethod = ClipMethod.INSIDE_ANY;
 
-		this.filterReturnNumberRange = [0, 7];
-		this.filterNumberOfReturnsRange = [0, 7];
-		this.filterGPSTimeRange = [-Infinity, Infinity];
-		this.filterPointSourceIDRange = [0, 65535];
+            this.elevationGradientRepeat = ElevationGradientRepeat.CLAMP;
 
-		this.potreeRenderer = null;
-		this.edlRenderer = null; 
-		this.pRenderer = null;
+            this.filterReturnNumberRange = [0, 7];
+            this.filterNumberOfReturnsRange = [0, 7];
+            this.filterGPSTimeRange = [-Infinity, Infinity];
+            this.filterPointSourceIDRange = [0, 65535];
 
-		this.scene = null;
-		this.sceneVR = null;
-		this.overlay = null;
-		this.overlayCamera = null;
+            this.potreeRenderer = null;
+            this.edlRenderer = null; 
+            this.pRenderer = null;
 
-		this.inputHandler = null;
-		this.controls = null;
+            this.scene = null;
+            this.sceneVR = null;
+            this.overlay = null;
+            this.overlayCamera = null;
 
-		this.clippingTool =  null;
-		this.transformationTool = null;
-		this.navigationCube = null;
-		this.compass = null;
-		
-		this.skybox = null;
-		this.clock = new THREE.Clock();
-		this.background = null;
-
-		 
-
-        
-  
-		if(args.noDragAndDrop){
-			
-		}else{
-			this.initDragAndDrop();
-		}
-
-		if(typeof Stats !== "undefined"){
-			this.stats = new Stats();
-			this.stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom
-			document.body.appendChild( this.stats.dom );
-		}
-
-		{
-			let canvas = this.renderer.domElement;
-			canvas.addEventListener("webglcontextlost", (e) => {
-				console.log(e);
-				this.postMessage("WebGL context lost. \u2639");
-
-				let gl = this.renderer.getContext();
-				let error = gl.getError();
-				console.log(error);
-			}, false);
-		}
-
-		{
-			this.overlay = new THREE.Scene();
-			this.overlayCamera = new THREE.OrthographicCamera(
-				0, 1,
-				1, 0,
-				-1000, 1000
-			);
-		}
-		
-		this.pRenderer = new Renderer(this.renderer);
-		
-		{
-			let near = 2.5;
-			let far = 10.0;
-			let fov = 90;
-			
-			this.shadowTestCam = new THREE.PerspectiveCamera(90, 1, near, far);
-			this.shadowTestCam.position.set(3.50, -2.80, 8.561);
-			this.shadowTestCam.lookAt(new THREE.Vector3(0, 0, 4.87));
-		}
-		
+            this.inputHandler = null;
+            this.controls = null;
 
-		let scene = new Scene(this.renderer);
-		
-		{ // create VR scene
-			this.sceneVR = new THREE.Scene();
+            this.clippingTool =  null;
+            this.transformationTool = null;
+            this.navigationCube = null;
+            this.compass = null;
+            
+            this.skybox = null;
+            this.clock = new THREE.Clock();
+            this.background = null;
 
-			// let texture = new THREE.TextureLoader().load(`${Potree.resourcePath}/images/vr_controller_help.jpg`);
+             
 
-			// let plane = new THREE.PlaneBufferGeometry(1, 1, 1, 1);
-			// let infoMaterial = new THREE.MeshBasicMaterial({map: texture});
-			// let infoNode = new THREE.Mesh(plane, infoMaterial);
-			// infoNode.position.set(-0.5, 1, 0);
-			// infoNode.scale.set(0.4, 0.3, 1);
-			// infoNode.lookAt(0, 1, 0)
-			// this.sceneVR.add(infoNode);
+            
+      
+            if(args.noDragAndDrop){
+                
+            }else{
+                this.initDragAndDrop();
+            }
 
-			// window.infoNode = infoNode;
-		}
+            if(typeof Stats !== "undefined"){
+                this.stats = new Stats();
+                this.stats.showPanel( 0 ); // 0: fps, 1: ms, 2: mb, 3+: custom
+                document.body.appendChild( this.stats.dom );
+            }
 
-		this.setScene(scene);
+            {
+                let canvas = this.renderer.domElement;
+                canvas.addEventListener("webglcontextlost", (e) => {
+                    console.log(e);
+                    this.postMessage("WebGL context lost. \u2639");
+
+                    let gl = this.renderer.getContext();
+                    let error = gl.getError();
+                    console.log(error);
+                }, false);
+            }
 
-		{
-			this.inputHandler = new InputHandler(this, this.scene.scene);
-			//this.inputHandler.setScene(this.scene);
-            //this.inputHandler.addInputListener(this);//add
+            {
+                this.overlay = new THREE.Scene();
+                this.overlayCamera = new THREE.OrthographicCamera(
+                    0, 1,
+                    1, 0,
+                    -1000, 1000
+                );
+            }
             
+            this.pRenderer = new Renderer(this.renderer);
             
+            {
+                let near = 2.5;
+                let far = 10.0;
+                let fov = 90;
+                
+                this.shadowTestCam = new THREE.PerspectiveCamera(90, 1, near, far);
+                this.shadowTestCam.position.set(3.50, -2.80, 8.561);
+                this.shadowTestCam.lookAt(new THREE.Vector3(0, 0, 4.87));
+            }
             
-			this.clippingTool = new ClippingTool(this);
-			this.transformationTool = new TransformationTool(this);
-			this.navigationCube = new NavigationCube(this);
-			this.navigationCube.visible = false;
 
-			this.compass = new Compass(this);
-            
+            let scene = new Scene(this.renderer);
             
-			//add----------
-            this.magnifier = new Magnifier(this);
-            this.reticule = new Reticule(this) 
-            this.scene.scene.add(this.magnifier) 
-            this.scene.scene.add(this.reticule)
-            this.mainViewport = new Viewport(  this.scene.view, this.scene.cameraP, {
-                left:0, bottom:0, width:1, height: 1, name:'MainView' 
-            }) 
-            this.viewports = [this.mainViewport]
-            
-            
-            this.mapViewer = new MapViewer($('#mapGaode')[0])
-            //-----------
-            
-            
-			this.createControls();
+            { // create VR scene
+                this.sceneVR = new THREE.Scene();
 
-			this.clippingTool.setScene(this.scene);
-			
-			let onPointcloudAdded = (e) => {
-				if (this.scene.pointclouds.length === 1) {
-					let speed = e.pointcloud.boundingBox.getSize(new THREE.Vector3()).length();
-					speed = speed / 2000;
-					this.setMoveSpeed(speed);
-				}
-			};
+                // let texture = new THREE.TextureLoader().load(`${Potree.resourcePath}/images/vr_controller_help.jpg`);
 
-			let onVolumeRemoved = (e) => {
-				this.inputHandler.deselect(e.volume);
-			};
+                // let plane = new THREE.PlaneBufferGeometry(1, 1, 1, 1);
+                // let infoMaterial = new THREE.MeshBasicMaterial({map: texture});
+                // let infoNode = new THREE.Mesh(plane, infoMaterial);
+                // infoNode.position.set(-0.5, 1, 0);
+                // infoNode.scale.set(0.4, 0.3, 1);
+                // infoNode.lookAt(0, 1, 0)
+                // this.sceneVR.add(infoNode);
 
-			this.addEventListener('scene_changed', (e) => {
-				this.inputHandler.setScene(e.scene);
-				this.clippingTool.setScene(this.scene);
-				
-				if(!e.scene.hasEventListener("pointcloud_added", onPointcloudAdded)){
-					e.scene.addEventListener("pointcloud_added", onPointcloudAdded);
-				}
+                // window.infoNode = infoNode;
+            }
 
-				if(!e.scene.hasEventListener("volume_removed", onPointcloudAdded)){
-					e.scene.addEventListener("volume_removed", onVolumeRemoved);
-				}
-				
-			});
+            this.setScene(scene);
 
-			this.scene.addEventListener("volume_removed", onVolumeRemoved);
-			this.scene.addEventListener('pointcloud_added', onPointcloudAdded);
-		}
+            {
+                this.inputHandler = new InputHandler(this, this.scene.scene);
+                //this.inputHandler.setScene(this.scene);
+                //this.inputHandler.addInputListener(this);//add
+                
+                
+                
+                this.clippingTool = new ClippingTool(this);
+                this.transformationTool = new TransformationTool(this);
+                this.navigationCube = new NavigationCube(this);
+                this.navigationCube.visible = false;
 
-		{ // set defaults
-			this.setFOV(60);
-			this.setEDLEnabled(false);
-			this.setEDLRadius(1.4);
-			this.setEDLStrength(0.4);
-			this.setEDLOpacity(1.0);
-			this.setClipTask(ClipTask.HIGHLIGHT);
-			this.setClipMethod(ClipMethod.INSIDE_ANY);
-			this.setPointBudget(1*1000*1000);
-			this.setShowBoundingBox(false);
-			this.setFreeze(false);
-			this.setControls(this.fpControls/* orbitControls */);
-			this.setBackground('gradient');
+                this.compass = new Compass(this);
+                
+                
+                //add----------
+                this.magnifier = new Magnifier(this);
+                this.reticule = new Reticule(this) 
+                this.scene.scene.add(this.magnifier) 
+                this.scene.scene.add(this.reticule)
+                this.mainViewport = new Viewport(  this.scene.view, this.scene.cameraP, {
+                    left:0, bottom:0, width:1, height: 1, name:'MainView' 
+                }) 
+                this.viewports = [this.mainViewport]
+                
+                
+                this.mapViewer = new MapViewer(mapArea/* $('#mapGaode')[0] */)
+                //-----------
+                
+                
+                this.createControls();
 
-			this.scaleFactor = 1;
+                this.clippingTool.setScene(this.scene);
+                
+                let onPointcloudAdded = (e) => {
+                    if (this.scene.pointclouds.length === 1) {
+                        let speed = e.pointcloud.boundingBox.getSize(new THREE.Vector3()).length();
+                        speed = speed / 2000;
+                        this.setMoveSpeed(speed);
+                    }
+                };
 
-			this.loadSettingsFromURL();
-		}
+                let onVolumeRemoved = (e) => {
+                    this.inputHandler.deselect(e.volume);
+                };
 
-		// start rendering!
-		//if(args.useDefaultRenderLoop === undefined || args.useDefaultRenderLoop === true){
-			//requestAnimationFrame(this.loop.bind(this));
-		//}
+                this.addEventListener('scene_changed', (e) => {
+                    this.inputHandler.setScene(e.scene);
+                    this.clippingTool.setScene(this.scene);
+                    
+                    if(!e.scene.hasEventListener("pointcloud_added", onPointcloudAdded)){
+                        e.scene.addEventListener("pointcloud_added", onPointcloudAdded);
+                    }
 
-		this.renderer.setAnimationLoop(this.loop.bind(this));
+                    if(!e.scene.hasEventListener("volume_removed", onPointcloudAdded)){
+                        e.scene.addEventListener("volume_removed", onVolumeRemoved);
+                    }
+                    
+                });
 
-		this.loadGUI = this.loadGUI.bind(this);
+                this.scene.addEventListener("volume_removed", onVolumeRemoved);
+                this.scene.addEventListener('pointcloud_added', onPointcloudAdded);
+            }
 
-		this.annotationTool = new AnnotationTool(this);
-		this.measuringTool = new MeasuringTool(this);
-		this.profileTool = new ProfileTool(this);
-		this.volumeTool = new VolumeTool(this);
+            { // set defaults
+                this.setFOV(60);
+                this.setEDLEnabled(false);
+                this.setEDLRadius(1.4);
+                this.setEDLStrength(0.4);
+                this.setEDLOpacity(1.0);
+                this.setClipTask(ClipTask.HIGHLIGHT);
+                this.setClipMethod(ClipMethod.INSIDE_ANY);
+                this.setPointBudget(1*1000*1000);
+                this.setShowBoundingBox(false);
+                this.setFreeze(false);
+                this.setControls(this.fpControls/* orbitControls */);
+                this.setBackground('gradient');
+
+                this.scaleFactor = 1;
+
+                this.loadSettingsFromURL();
+            }
+
+            // start rendering!
+            //if(args.useDefaultRenderLoop === undefined || args.useDefaultRenderLoop === true){
+                //requestAnimationFrame(this.loop.bind(this));
+            //}
+         
+
+            this.renderer.setAnimationLoop(this.loop.bind(this));
+
+            this.loadGUI = this.loadGUI.bind(this);
+
+            this.annotationTool = new AnnotationTool(this);
+            this.measuringTool = new MeasuringTool(this);
+            this.profileTool = new ProfileTool(this);
+            this.volumeTool = new VolumeTool(this);
 
 		}catch(e){
 			this.onCrash(e);
 		}
         
-        {
+        {//add
             let pointDensity = ''
             Object.defineProperty(Potree.settings , "pointDensity",{ 
                 get: function() {
@@ -1391,8 +1370,8 @@ export class Viewer extends ViewerBase{
 				});
 			});
 
-			this.mapView = new MapView(this);
-			this.mapView.init();
+			/* this.mapView = new MapView(this);
+			this.mapView.init(); */
 
 			i18n.init({
 				lng: 'en',
@@ -1887,8 +1866,8 @@ export class Viewer extends ViewerBase{
             }) 
 		}
 		 
-        this.viewports.forEach(e=>{//判断camera画面是否改变
-            if(e.hasChanged()){
+        /* this.viewports.forEach(e=>{//判断camera画面是否改变
+            if(e.cameraChanged()){
                 this.dispatchEvent({
                     type: "camera_changed", 
                     camera: e.camera,
@@ -1896,8 +1875,10 @@ export class Viewer extends ViewerBase{
                 })
                  
             }
-        })
-         
+        }) */
+        
+        this.cameraChanged()//判断camera画面是否改变
+        
         /* {//判断camera画面是否改变
 			if(this._previousCamera === undefined){
 				this._previousCamera = this.scene.getActiveCamera().clone();
@@ -2006,7 +1987,7 @@ export class Viewer extends ViewerBase{
 
  
 
-        if(isViewport)return
+        //if(isViewport)return
         const tStart = performance.now();
         const campos = camera.position;
         let closestImage = Infinity;
@@ -2019,7 +2000,14 @@ export class Viewer extends ViewerBase{
         }
         const tEnd = performance.now();
 
-        if(result.lowestSpacing !== Infinity){
+
+        //改:不根据点云修改视野near far
+        var near = camera.near, far = camera.far
+        if(Potree.settings.limitFar){
+            camera.near = 0.1;
+            camera.far = Potree.settings.cameraFar; 
+        }else if(result.lowestSpacing !== Infinity){
+            
             let near = result.lowestSpacing * 10.0;
             let far = -this.getBoundingBox().applyMatrix4(camera.matrixWorldInverse).min.z;
 
@@ -2035,13 +2023,16 @@ export class Viewer extends ViewerBase{
             camera.near = near;
             camera.far = far;
         }else{
-            // don't change near and far in this case
-        }
+             
+        } 
 
-        if(this.scene.cameraMode == CameraMode.ORTHOGRAPHIC) {
+        if(this.scene.cameraMode == CameraMode.ORTHOGRAPHIC) {//???
             camera.near = -camera.far;
         }
-        
+        if(near != camera.near || far != camera.far){
+            camera.updateProjectionMatrix()
+        }
+        //注:pointcloud.visibleNodes会随着near far自动更新
     }
 
 
@@ -2358,7 +2349,7 @@ export class Viewer extends ViewerBase{
         
         
         if(!params.magnifier){//为什么要在点云之后渲染,否则透明失效 、 会被点云覆盖 
-            this.setCameraLayers(camera, ['marker','reticule']) //透明贴图层 skybox 、reticule marker 不能遮住测量线
+            this.setCameraLayers(camera, ['marker','reticule','route']) //透明贴图层 skybox 、reticule marker 不能遮住测量线
             this.renderer.render(this.scene.scene, camera); 
         } 
         this.dispatchEvent({type: "render.pass.scene", viewer: viewer});