소스 검색

加了navcube

xzw 2 년 전
부모
커밋
058068f575

+ 4 - 2
libs/three.js/lines/LineMaterial.js

@@ -867,10 +867,12 @@ class LineMaterial extends ShaderMaterial {
                 this.updateDepthParams(e)
             } 
         }
-            
+        
+        
+        let viewer = parameters.viewer || window.viewer 
         this.setValues( parameters );
         
-        let viewport = viewer.mainViewport; 
+        let viewport = viewer.viewports[0]; 
         this.events.setSize({viewport})  
         
         viewer.addEventListener('resize', this.events.setSize)  

+ 4 - 4
src/custom/modules/panos/Images360.js

@@ -126,12 +126,12 @@ export class Images360 extends THREE.EventDispatcher{
                 Potree.settings.unableNavigate || this.flying  || !e.isTouch && e.button != THREE.MOUSE.LEFT || e.drag &&  e.drag.object //拖拽结束时不算
                || Potree.settings.editType == 'pano' && viewer.modules.PanoEditor.activeViewName != 'mainView'
                 ||   Potree.settings.editType == 'merge' && !e.intersectPoint || viewer.inputHandler.hoveredElements[0] && viewer.inputHandler.hoveredElements[0].isModel && e.intersectPoint.distance > viewer.inputHandler.hoveredElements[0].distance
+                 || e.hoverViewport != viewer.mainViewport //如数据集校准其他viewport
+                ||  viewer.mainViewport.camera.type == 'OrthographicCamera'  //暂时不支持
+               
             )  return 
              
-            if(e.hoverViewport != viewer.mainViewport){ //如数据集校准其他viewport
-                 return
-            }
-              
+            
             if(!Potree.settings.dblToFocusPoint/*  && this.currentPano */){//双击不会focus点云 或者 已经focusPano了
                 this.flyToPanoClosestToMouse()   
             }

+ 26 - 3
src/custom/objects/tool/Measure.js

@@ -454,7 +454,7 @@ export class Measure extends ctrlPolygon{
     
     
     setSelected(state, hoverObject){//add
-        //console.log('setSelected',state, hoverObject)
+        //console.log('setSelected', state, hoverObject)
         hoverObject && (this.selectStates[hoverObject] = state)
         let absoluteState = false
         for(var i in this.selectStates){
@@ -647,6 +647,29 @@ export class Measure extends ctrlPolygon{
         
     }
     
+    focus(){  
+        viewer.focusOnObject(this, 'measure')
+        
+        if(this.clickSelected)return
+        this.setSelected(true, 'focus')
+        this.dispatchEvent({type:'selected', state:true})
+        this.clickSelected = true
+        //viewer.dispatchEvent({type:'selectMeasure', measure:this})
+        let cancelSelect = ()=>{
+            this.clickSelected = false
+            this.removeEventListener('cancelSelect', cancelSelect)
+            viewer.removeEventListener('global_click', cancelSelect) 
+            this.setSelected(false, 'focus') 
+            this.dispatchEvent({type:'selected', state:false})
+        }
+        setTimeout(()=>{
+            this.addEventListener('cancelSelect', cancelSelect)
+            viewer.addEventListener('global_click', cancelSelect) 
+        },10)
+    }
+     
+    
+    
     createEdgeLabel(name, hasHoverEvent){
         const edgeLabel = new TextSprite(
             $.extend(hasHoverEvent ? mainLabelProp : subLabelProp,{sizeInfo: labelSizeInfo,  name:name||'edgeLabel'})
@@ -659,7 +682,7 @@ export class Measure extends ctrlPolygon{
                 this.setSelected(false, 'edgeLabel')
             })  
             edgeLabel.addEventListener('click',()=>{
-                this.isNew || viewer.focusOnObject(this, 'measure')
+                if(!this.isNew) this.focus()
             })
         }
         edgeLabel.visible = false
@@ -693,7 +716,7 @@ export class Measure extends ctrlPolygon{
             this.setSelected(false, 'areaLabel')
         }) 
         areaLabel.addEventListener('click',()=>{
-            this.isNew || viewer.focusOnObject(this, 'measure')
+            if(!this.isNew) this.focus()
         })
         Potree.Utils.setObjectLayers(areaLabel, 'measure' )
         areaLabel.setVisible(false) 

+ 2 - 2
src/custom/start.js

@@ -10,13 +10,13 @@ import './three.shim.js'
 import "./potree.shim.js"
  
 
-export function start(dom, mapDom, number ){ //t-Zvd3w0m
+export function start(dom, navDom, number ){ //t-Zvd3w0m
     
     Potree.settings.number = number || 't-o5YMR13'// 't-iksBApb'// 写在viewer前
   
     if(browser.urlHasValue('timing'))Potree.measureTimings = 1
     
-    let viewer = new Potree.Viewer(dom , mapDom); 
+    let viewer = new Potree.Viewer(dom , navDom); 
 	viewer.setEDLEnabled(false);
     viewer.setFOV(Potree.config.view.fov); 
      

+ 2 - 2
src/custom/utils/DrawUtil.js

@@ -90,10 +90,10 @@ var LineDraw = {
             dashWithDepth:!!o.dashWithDepth,//只在被遮住的部分显示虚线
             useDepth: !!o.useDepth,  
             supportExtDepth,
-            
+             
         })
         
-        
+         
         
 		var mat = new LineMaterial(params)
          

+ 21 - 8
src/custom/utils/SplitScreen.js

@@ -75,11 +75,11 @@ class SplitScreen extends THREE.EventDispatcher{
         let info = {bound} 
         let {boundSize, boundCenter} = this.getViewBound(viewport)
         
-        
-        
+        this.setShiftTarget(viewport, boundCenter)
+        /* 
         viewport.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), boundCenter )  
         viewport.targetPlane.projectPoint(center, viewport.shiftTarget)  //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
-        
+         */
         info.endPosition = this.getPosOutOfModel(viewport, boundSize) 
         
         //if(viewport.name == 'mapViewport')info.endPosition.z = Math.max(Potree.config.map.cameraHeight, info.endPosition.z) 
@@ -117,9 +117,10 @@ class SplitScreen extends THREE.EventDispatcher{
         viewer.viewports.forEach((viewport, i )=>{
             if(viewport != viewer.mainViewport){
                 let {boundSize, boundCenter} = this.getViewBound(viewport)
-                viewport.targetPlane.setFromNormalAndCoplanarPoint( viewport.view.direction.clone(), boundCenter) 
+                /* viewport.targetPlane.setFromNormalAndCoplanarPoint( viewport.view.direction.clone(), boundCenter) 
                 viewport.targetPlane.projectPoint(viewport.view.position, viewport.shiftTarget)  //target转换到过模型中心的平面,以保证镜头一定在模型外 this.shiftTarget是得到的
-         
+                */ 
+                this.setShiftTarget(viewport, boundCenter)
                  let endPosition = this.getPosOutOfModel(viewport, boundSize) 
                  //if(viewport.name == 'mapViewport')endPosition.z = Math.max(Potree.config.map.cameraHeight, endPosition.z) 
                  viewport.view.position.copy(endPosition)
@@ -127,15 +128,27 @@ class SplitScreen extends THREE.EventDispatcher{
         })  
     }  
      
+     
+     
+     
+    setShiftTarget(viewport, center){
+        if(!viewport.targetPlane ){
+            viewport.targetPlane = new THREE.Plane()
+            viewport.shiftTarget = new THREE.Vector3 //project在targetPlane上的位置
+        }
+         
+        viewport.targetPlane.setFromNormalAndCoplanarPoint(viewport.view.direction, center ) 
+        viewport.targetPlane.projectPoint(viewport.view.position,  viewport.shiftTarget )  //target转换到过模型中心的平面,以保证镜头一定在模型外
+        
+    }
+     
     rotateSideCamera(viewport, angle){//侧视图绕模型中心水平旋转
          
         //let {boundSize, center} = viewer.bound
         let {boundSize, boundCenter } = this.getViewBound(viewport)  
         let center = this.focusCenter || boundCenter //旋转中心,一般是所有模型的中心,除非想指定中心点
-        
+        this.setShiftTarget(viewport, center)
         //找到平移向量
-        viewport.targetPlane.setFromNormalAndCoplanarPoint(viewport.view.direction  , center ) 
-        viewport.targetPlane.projectPoint(viewport.view.position,  viewport.shiftTarget )  //target转换到过模型中心的平面,以保证镜头一定在模型外
         let vec = new THREE.Vector3().subVectors(center, viewport.shiftTarget)//相对于中心的偏移值,旋转后偏移值也旋转
         
         //旋转

+ 7 - 5
src/custom/utils/math.js

@@ -1,8 +1,8 @@
 
 import * as THREE from "../../../libs/three.js/build/three.module.js";
 import searchRings from "./searchRings.js";
-
-
+import {ExtendView} from '../../viewer/ExtendView.js'
+ 
 
 var math = {
     getBaseLog(x, y) {//返回以 x 为底 y 的对数(即 logx y) .  Math.log 返回一个数的自然对数
@@ -592,9 +592,11 @@ var math = {
     },
 
     getQuaFromPosAim( position, target ){ 
-        let matrix = (new THREE.Matrix4).lookAt(position, target, new THREE.Vector3(0,0,1))
-        return (new THREE.Quaternion).setFromRotationMatrix(matrix)
-        
+        /* let matrix = (new THREE.Matrix4).lookAt(position, target, new THREE.Vector3(0,0,1)) //这里垂直的话会默认给一个右向所以不这么写
+        return (new THREE.Quaternion).setFromRotationMatrix(matrix) */
+        let view = new ExtendView()
+        view.direction = new THREE.Vector3().subVectors(target,position) 
+        return view.quaternion
     },
     
     

+ 93 - 59
src/custom/viewer/ViewerNew.js

@@ -10,7 +10,7 @@ import {Renderer} from "../../PotreeRendererNew.js";
 import {EDLRenderer} from "../../viewer/EDLRendererNew.js";
 import {HQSplatRenderer} from "../../viewer/HQSplatRenderer.js";
                                                                 
-import {NavigationCube} from '../../viewer/NavigationCube.js'
+import {NavCubeViewer} from '../../viewer/NavigationCube.js'
   
 //import {MapView} from "../viewer/map.js"; 
 import {ProfileWindow, ProfileWindowController} from "../../viewer/profile.js";
@@ -69,23 +69,32 @@ import {OrbitControls} from "../../navigation/OrbitControlsNew.js";
 
 import { ClassificationScheme } from "../../materials/ClassificationScheme.js";
 import { VRButton } from '../../../libs/three.js/extra/VRButton.js';
+
+
+ 
+ 
+ 
+ 
+ 
+ 
+ 
  
 const manager = new THREE.LoadingManager(); 
 let loaders = {}
 
-let mapArea; 
+let navCubeArea; 
 let shelterHistory = []
 
 
 
 export class Viewer extends ViewerBase{
 	
-	constructor(domElement, mapArea_, args = {}){
+	constructor(domElement, navCubeArea_, args = {}){
 		super(domElement, $.extend(args,{name:'mainViewer', antialias:true, preserveDrawingBuffer:true}));
         //注:viewer因为要分屏,尤其是四屏,preserveDrawingBuffer需要为true, 否则无法局部clear 
         
         window.viewer = this
-        mapArea = mapArea_                 
+        navCubeArea = navCubeArea_                 
          
         this.modules = { 
             
@@ -154,7 +163,14 @@ export class Viewer extends ViewerBase{
               
         })
         
-         
+        //add 
+            navCubeArea = $("<div id='navCube' style='position:fixed;width:100px;height:100px;top:0;right:12px;'></div>")
+            $(domElement).append(navCubeArea) 
+            let homeBtn = $("<div id='home' style='position:fixed;width:10px;height:10px;top:0;right:0;background:#fff;'></div>")
+            $(domElement).append(homeBtn) 
+            homeBtn.on('click',()=>{
+                this.navCubeViewer.pushHomeBtn()
+            }) 
             
         try{
             
@@ -192,16 +208,8 @@ export class Viewer extends ViewerBase{
                     $(domElement).append(potreeMap);
                 }
                 
-                //add
-                /* { 
-                    if(!mapArea && Potree.settings.editType != 'merge'){
-                        $(domElement).append($("<div id='potree_labels'></div>"))
-                        
-                        mapArea = $("<div id='mapGaode'></div>")
-                        $(domElement).append(mapArea)
-                        mapArea = mapArea[0]
-                    } 
-                } */
+                
+                
                  
              
                /*  let domRoot = this.renderer.domElement.parentElement; 
@@ -404,6 +412,11 @@ export class Viewer extends ViewerBase{
                 this.scene.scene.add(this.magnifier) 
                 this.scene.scene.add(this.reticule)
                 
+                //add:
+                if(navCubeArea){
+                    this.navCubeViewer = new NavCubeViewer(navCubeArea[0], this.mainViewport)
+                }
+                 
                  
                 
                 this.inputHandler = new InputHandler(this, this.scene.scene);
@@ -412,9 +425,9 @@ export class Viewer extends ViewerBase{
                 
                 this.clippingTool = new ClippingTool(this);
                 this.transformationTool = new TransformationTool(this);
-                this.navigationCube = new NavigationCube(this);
+                /* this.navigationCube = new NavigationCube(this);
                 this.navigationCube.visible = false;
-
+                */
                 
                 
                  
@@ -1670,9 +1683,9 @@ export class Viewer extends ViewerBase{
 		this.controls.stop();
 	};
 
-	toggleNavigationCube() {
+	/* toggleNavigationCube() {
 		this.navigationCube.visible = !this.navigationCube.visible;
-	}
+	} */
 
 	/* setView(pos, view) {
 		if(!pos) return;
@@ -1699,46 +1712,49 @@ export class Viewer extends ViewerBase{
 		}
 	} */
 	
-	setTopView(view){
+	setTopView(view, dur){
         view = view || this.scene.view
 		view.setCubeView("top")
 
-		this.fitToScreen();
+		this.fitToScreen(1, dur);
 	};
 	
-	setBottomView(){
-		this.scene.view.yaw = -Math.PI;
-		this.scene.view.pitch = Math.PI / 2;
+	setBottomView(view, dur){
+        view = view || this.scene.view
+		view.yaw = -Math.PI;
+		view.pitch = Math.PI / 2;
 		
-		this.fitToScreen();
+		this.fitToScreen(1, dur);
 	};
 
-	setFrontView(view){
+	setFrontView(view, dur){
         view = view || this.scene.view 
 		view.yaw = 0;
 		view.pitch = 0;
 
-		this.fitToScreen();
+		this.fitToScreen(1, dur);
 	};
 	
-	setBackView(view){
+	setBackView(view, dur){
         view = view || this.scene.view 
 		view.yaw = Math.PI;
 		view.pitch = 0;
 		
-		this.fitToScreen();
+		this.fitToScreen(1, dur);
 	};
 
-	setLeftView(){
-		this.scene.view.yaw = -Math.PI / 2;
-		this.scene.view.pitch = 0;
+	setLeftView(view, dur){
+        view = view || this.scene.view 
+		view.yaw = -Math.PI / 2;
+		view.pitch = 0;
 
-		this.fitToScreen();
+		this.fitToScreen(1, dur);
 	};
 
-	setRightView () {
-		this.scene.view.yaw = Math.PI / 2;
-		this.scene.view.pitch = 0;
+	setRightView (view, dur) {
+        view = view || this.scene.view 
+		view.yaw = Math.PI / 2;
+		view.pitch = 0;
 
 		this.fitToScreen();
 	};
@@ -1756,6 +1772,8 @@ export class Viewer extends ViewerBase{
 		for(let pointcloud of this.scene.pointclouds) {
 			pointcloud.material.useOrthographicCamera = mode == CameraMode.ORTHOGRAPHIC;
 		}
+        
+        this.updateScreenSize({forceUpdateSize:true})//reset camera.left  and projectionMatrix
 	}
 
 	getProjection(){
@@ -2481,7 +2499,7 @@ export class Viewer extends ViewerBase{
 		}
 		
 		{ // update navigation cube
-			this.navigationCube.update(camera.rotation);
+			 this.navCubeViewer.update(delta);
 		}
 
 		this.updateAnnotations();
@@ -3426,11 +3444,11 @@ export class Viewer extends ViewerBase{
         duration = duration == void 0 ? 1200 : duration;      
         let camera = viewer.scene.getActiveCamera()
         let cameraPos = camera.position.clone()
-         
-        if(camera.type == 'OrthographicCamera'){
+        let boundSize  
+        /* if(camera.type == 'OrthographicCamera'){
             return console.error('focusOnObject暂不支持OrthographicCamera。因情况复杂,请视情况使用splitScreenTool.viewportFitBound')
         }
-        
+         */
         let getPosWithFullBound = (points, boundingBox, target, cameraPos  )=>{//使boundingBox差不多占满屏幕时的相机到target的距离
             // points 和 boundingBox 至少有一个
             
@@ -3458,8 +3476,8 @@ export class Viewer extends ViewerBase{
                 bound = boundingBox.applyMatrix4(inv);
                 scale = 0.9; 
             }
-            let boundSize = bound.getSize(new THREE.Vector3)
             
+            boundSize = bound.getSize(new THREE.Vector3)
             
             {
                 
@@ -3469,15 +3487,19 @@ export class Viewer extends ViewerBase{
                 boundSize.x = Math.max(min, boundSize.x)
                 boundSize.y = Math.max(min, boundSize.y)
             }
-            
-            
-            let aspect = boundSize.x / boundSize.y
-            if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定
-                dis = boundSize.y/2/ Math.tan(THREE.Math.degToRad(camera.fov / 2)) + boundSize.z/2 
+            if(camera.type == 'OrthographicCamera'){
+                dis = boundSize.length() / 2
             }else{
-                let hfov = cameraLight.getHFOVForCamera(camera, true);
-                dis = boundSize.x/2 / Math.tan(hfov / 2) + boundSize.z/2
+                let aspect = boundSize.x / boundSize.y
+                if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定
+                    dis = boundSize.y/2/ Math.tan(THREE.Math.degToRad(camera.fov / 2)) + boundSize.z/2 
+                }else{
+                    let hfov = cameraLight.getHFOVForCamera(camera, true);
+                    dis = boundSize.x/2 / Math.tan(hfov / 2) + boundSize.z/2
+                }  
             }
+            
+            
             dis = Math.max(0.1,dis)
             
             //三个顶点以上的由于measure的中心不等于bound的中心,所以点会超出bound外。 且由于视椎近大远小,即使是两个点的,bound居中后线看上去仍旧不居中.
@@ -3746,8 +3768,11 @@ export class Viewer extends ViewerBase{
                 return result           
             }
         }else if(object.boundingBox && type == 'boundingBox'){//使屏幕刚好看全boundingBox
-            target = object.boundingBox.getCenter(new THREE.Vector3)
-            position = getPosWithFullBound(object.points, object.boundingBox, target, cameraPos  )
+            target = object.boundingBox.getCenter(new THREE.Vector3) 
+            if(o.dir){ //指定方向
+                cameraPos.copy(target).sub(o.dir)
+            } 
+            position = getPosWithFullBound(object.points, object.boundingBox.clone(), target, cameraPos  )
             if(Potree.settings.displayMode == 'showPanos'){//全景 (比较难校准)
                 let pano = viewer.images360.fitPanoTowardPoint({ 
                     point : position,
@@ -3762,9 +3787,7 @@ export class Viewer extends ViewerBase{
                 return {promise:deferred.promise() }
                 //出现过到达位置后测量线标签闪烁的情况
             }else{
-               /*  if(o.dontChangeCamDir){
-                    target = null
-                } */
+               
             }
             
         }
@@ -3781,12 +3804,23 @@ export class Viewer extends ViewerBase{
         }else{//立体
             
         } */
-
-        viewer.scene.view.setView({position, target, duration, callback:()=>{
-                //console.log('focusOnObjectSuccess: '+object.name,  type)
-                deferred.resolve()
-            }
-        })
+        if(camera.type == "OrthographicCamera"){   
+            viewer.scene.view.moveOrthoCamera(this.mainViewport,  { endPosition:position, target ,
+                boundSize, 
+                callback:()=>{
+                    //console.log('focusOnObjectSuccess: '+object.name,  type)
+                    deferred.resolve()
+                }
+            }, duration)
+        }else{
+            viewer.scene.view.setView({position, target, duration, callback:()=>{
+                    //console.log('focusOnObjectSuccess: '+object.name,  type)
+                    deferred.resolve()
+                }
+            })
+        }
+        
+        
          
         this.dispatchEvent({type:'focusOnObject', CamTarget:target, position}) //给controls发送信息
         

+ 17 - 14
src/navigation/FirstPersonControlsNew.js

@@ -18,6 +18,7 @@ import {Utils} from "../utils.js";
 import cameraLight from "../custom/utils/cameraLight.js"; 
 import Common from "../custom/utils/Common.js"; 
 import math from "../custom/utils/math.js"; 
+
  
 let Buttons = Potree.defines.Buttons 
 export class FirstPersonControls extends THREE.EventDispatcher {
@@ -69,7 +70,7 @@ export class FirstPersonControls extends THREE.EventDispatcher {
         //this.enableChangePos = true
         
         this.viewer.addEventListener('camera_changed',(e)=>{
-            if(this.viewer.name == 'mapViewer' || e.changeInfo && e.changeInfo.positionChanged && !viewer.mainViewport.view.isFlying() ){
+            if(this.viewer.name == 'mapViewer' || e.changeInfo && e.changeInfo.positionChanged && !window.viewer.mainViewport.view.isFlying() ){
                 this.setFPCMoveSpeed(e.viewport)
             } 
         })
@@ -194,10 +195,16 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                 
                 if(camera.type == "OrthographicCamera"){
                    
-                    //console.log(e.drag.pointerDelta, e.pointer, e.drag.end)
+                     //console.log(e.drag.pointerDelta, e.pointer, e.drag.end)
                     let moveVec = Utils.getOrthoCameraMoveVec(e.drag.pointerDelta, camera )//最近一次移动向量
                   
-                    let pointclouds;
+                    if(e.buttons === Buttons.RIGHT  ){ 
+                    
+                        return viewer.navCubeViewer.rotateSideCamera( -e.drag.pointerDelta.x)
+     
+                    }
+                  
+                    /*let pointclouds;
                     let Alignment = window.viewer.modules.Alignment
                     let MergeEditor = window.viewer.modules.MergeEditor
                     let handleState = Alignment.handleState
@@ -228,16 +235,12 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                             return MergeEditor.rotateSideCamera(-e.drag.pointerDelta.x)
                         }  
                     
-                    }else{ 
-                        /* if(Alignment.selectedClouds && Alignment.selectedClouds.length){//多个点云
-                            pointclouds = a && e.drag.intersectStart.pointclouds && Common.getMixedSet(Alignment.selectedClouds, e.drag.intersectStart.pointclouds).length && Alignment.selectedClouds
-                            
-                        }else{ */
-                            pointclouds = a && e.drag.intersectStart.pointcloud && [e.drag.intersectStart.pointcloud]
-                        //} 
-                    }
+                    }else{  
+                        pointclouds = a && e.drag.intersectStart.pointcloud && [e.drag.intersectStart.pointcloud]
+                     
+                    } */
                       
-                    if(pointclouds){
+                    /* if(pointclouds){
                         if(handleState == 'translate' && viewport.alignment.translateVec){//只能沿某个方向移动
                             moveVec.projectOnVector(viewport.alignment.translateVec)
                         } 
@@ -250,9 +253,9 @@ export class FirstPersonControls extends THREE.EventDispatcher {
                             pointclouds, 
                             camera
                         }) 
-                    }else{  
+                    }else{ */  
                         this.translationWorldDelta.add(moveVec.negate())  
-                    }
+                    //}
                      
                 }else{ //perspectiveCamera: 
                     if(e.drag.intersectStart){//如果拖拽着点云 

+ 5 - 3
src/navigation/InputHandlerNew.js

@@ -399,8 +399,8 @@ export class InputHandler extends THREE.EventDispatcher {
       
         
         //if(isTouch || !Potree.settings.intersectWhenHover ){ 
-        if(!this.dragViewport.view.isFlying()){
-            this.hoveredElements = this.getHoveredElements();
+        if(!this.dragViewport.view.isFlying()){ 
+            this.hoveredElements = this.getHoveredElements(); 
             this.intersect = this.getIntersect(viewport) //更新intersect,避免在没有mousemove但flyToPano后intersect未更新。
             //this.intersect = this.getWholeIntersect()  
         }
@@ -1391,7 +1391,9 @@ export class InputHandler extends THREE.EventDispatcher {
             return order2-order1
         }) // 降序
         
-        
+        /* if(intersections.length == 0){
+            console.log('no')
+        } */
         //console.log('getHoveredElement ', intersections)
 		return intersections;
 	}

+ 33 - 23
src/navigation/OrbitControlsNew.js

@@ -22,7 +22,7 @@ let minRadius = 2
  
 export class OrbitControls extends THREE.EventDispatcher{
 	
-	constructor(viewer){
+	constructor(viewer, viewport){
 		super();
 		
 		this.viewer = viewer;
@@ -33,9 +33,10 @@ export class OrbitControls extends THREE.EventDispatcher{
 
 		this.rotationSpeed = 3;  //旋转速度
         
-         
+        this.setCurrentViewport({hoverViewport:viewport, force:true}) //this.currentViewport = viewport
+        
 
-		this.fadeFactor = 100;
+		this.fadeFactor = 20;
 		this.yawDelta = 0;
 		this.pitchDelta = 0;
 		this.panDelta = new THREE.Vector2(0, 0);
@@ -62,7 +63,7 @@ export class OrbitControls extends THREE.EventDispatcher{
             if(!this.enabled)return
  
             let viewport = e.dragViewport;
-            if(!viewport || viewport.camera.type == "OrthographicCamera" )return
+            if(!viewport /* || viewport.camera.type == "OrthographicCamera"  */)return
             //let camera = viewport.camera 
           
 
@@ -113,7 +114,7 @@ export class OrbitControls extends THREE.EventDispatcher{
                 var scale = this.dollyEnd.length() / this.dollyStart.length() 
                   
                 this.dollyStart.copy(this.dollyEnd); 
-                this.radiusDelta = (1-scale) * this.scene.view.radius 
+                this.radiusDelta = (1-scale) * this.currentViewport.view.radius 
 			  
                 //------------------------
                 //平移
@@ -148,7 +149,7 @@ export class OrbitControls extends THREE.EventDispatcher{
 
 		let scroll = (e) => {
             if(!this.enabled)return
-			let resolvedRadius = this.scene.view.radius + this.radiusDelta;
+			let resolvedRadius = this.currentViewport.view.radius + this.radiusDelta;
             if(resolvedRadius < 0.1 && e.delta>0)return; //防止缩放太小,导致很慢
 			this.radiusDelta += -e.delta * resolvedRadius * 0.1;
             
@@ -186,7 +187,7 @@ export class OrbitControls extends THREE.EventDispatcher{
 				let currDist = Math.sqrt(currDX * currDX + currDY * currDY);
 
 				let delta = currDist / prevDist;
-				let resolvedRadius = this.scene.view.radius + this.radiusDelta;
+				let resolvedRadius = this.currentViewport.view.radius + this.radiusDelta;
 				let newRadius = resolvedRadius / delta;
 				this.radiusDelta = newRadius - resolvedRadius;
 
@@ -261,6 +262,15 @@ export class OrbitControls extends THREE.EventDispatcher{
 	setScene (scene) {
 		this.scene = scene;
 	}
+    
+    setCurrentViewport(o={}){//add
+        if(!this.enabled && !o.force )return
+        if(o.hoverViewport && this.currentViewport != o.hoverViewport ){
+            this.currentViewport = o.hoverViewport  
+			 
+        } 
+    }
+    
     setEnable(enabled){
         this.enabled = enabled
     }
@@ -296,11 +306,11 @@ export class OrbitControls extends THREE.EventDispatcher{
 			let nodes = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, ray);
 			let lastNode = nodes[nodes.length - 1];
 			let radius = lastNode.getBoundingSphere(new THREE.Sphere()).radius;
-			targetRadius = Math.min(this.scene.view.radius, radius);
+			targetRadius = Math.min(this.currentViewport.view.radius, radius);
 			targetRadius = Math.max(minimumJumpDistance, targetRadius);
 		}
 
-		let d = this.scene.view.direction.multiplyScalar(-1);
+		let d = this.currentViewport.view.direction.multiplyScalar(-1);
 		let cameraTargetPosition = new THREE.Vector3().addVectors(I.location, d.multiplyScalar(targetRadius));
 		// TODO Unused: let controlsTargetPosition = I.location;
 
@@ -313,19 +323,19 @@ export class OrbitControls extends THREE.EventDispatcher{
 			tween.easing(easing);
 			this.tweens.push(tween);
 
-			let startPos = this.scene.view.position.clone();
+			let startPos = this.currentViewport.view.position.clone();
 			let targetPos = cameraTargetPosition.clone();
-			let startRadius = this.scene.view.radius;
+			let startRadius = this.currentViewport.view.radius;
 			let targetRadius = cameraTargetPosition.distanceTo(I.location);
 
 			tween.onUpdate(() => {
 				let t = value.x;
-				this.scene.view.position.x = (1 - t) * startPos.x + t * targetPos.x;
-				this.scene.view.position.y = (1 - t) * startPos.y + t * targetPos.y;
-				this.scene.view.position.z = (1 - t) * startPos.z + t * targetPos.z;
+				this.currentViewport.view.position.x = (1 - t) * startPos.x + t * targetPos.x;
+				this.currentViewport.view.position.y = (1 - t) * startPos.y + t * targetPos.y;
+				this.currentViewport.view.position.z = (1 - t) * startPos.z + t * targetPos.z;
 
-				this.scene.view.radius = (1 - t) * startRadius + t * targetRadius;
-				this.viewer.setMoveSpeed(this.scene.view.radius);
+				this.currentViewport.view.radius = (1 - t) * startRadius + t * targetRadius;
+				this.viewer.setMoveSpeed(this.currentViewport.view.radius);
 			});
 
 			tween.onComplete(() => {
@@ -351,7 +361,7 @@ export class OrbitControls extends THREE.EventDispatcher{
         
         if(!I || !object)return;
         
-        let dis = this.scene.view.position.distanceTo(I); 
+        let dis = this.currentViewport.view.position.distanceTo(I); 
         
         
         let bound = object.boundingBox.clone().applyMatrix4(object.matrixWorld)
@@ -373,8 +383,8 @@ export class OrbitControls extends THREE.EventDispatcher{
 
 	update (delta) {
         if(!this.enabled)return
-		let view = this.scene.view;
-
+		let view = this.currentViewport.view//this.currentViewport.view;
+        let camera = this.currentViewport.camera
 
 
 
@@ -428,16 +438,16 @@ export class OrbitControls extends THREE.EventDispatcher{
 			view.yaw = yaw;
 			view.pitch = pitch;
 
-			let V = this.scene.view.direction.multiplyScalar(-view.radius);
+			let V = this.currentViewport.view.direction.multiplyScalar(-view.radius);
 			let position = new THREE.Vector3().addVectors(pivot, V);
 
 			view.position.copy(position);
 		}
 
-		{ // apply pan
+		if(camera.type != 'OrthographicCamera'){ // apply pan
 			/* let progression = Math.min(1, this.fadeFactor * delta);
 			let panDistance = progression * view.radius * 3; */
-            let camera = this.scene.getActiveCamera()
+            
             let panDistance = 2 * view.radius * Math.tan(THREE.Math.degToRad(camera.fov / 2));//参照4dkk。 平移target(也就是平移镜头位置),但还是难以保证跟手(navvis也不一定跟手,但是很奇怪在居中时中心点居然是跟手的,可能计算方式不同)
             //计算了下确实是这么算的。 平移pivot。 
             
@@ -469,7 +479,7 @@ export class OrbitControls extends THREE.EventDispatcher{
 
 		{
 			let speed = view.radius;
-			this.viewer.setMoveSpeed(speed);
+			this.viewer.setMoveSpeed && this.viewer.setMoveSpeed(speed);
 		}
 
 		{ // decelerate over time

+ 32 - 15
src/viewer/ExtendView.js

@@ -39,13 +39,19 @@ class ExtendView extends View {
         return rotation
     }
      
-    set rotation(rotation){
+    set rotation(rotation){//这个在数字很小(垂直向上看)的时候水平旋转精度可能损失,导致突变到另一个角度去了,用 set quaternion比较好
         //因为 rotation的y不一定是0 , 所以不能直接逆着写。
         this.direction = new THREE.Vector3(0,0,-1).applyEuler(rotation)
     }
     
    
+    get quaternion(){
+        return new THREE.Quaternion().setFromEuler(this.rotation)
+    }
     
+    set quaternion(q){
+        this.direction = new THREE.Vector3(0,0,-1).applyQuaternion(q)
+    }
     
     copy(a){
         Common.CopyClassObject(this, a, {ignoreList: ['_listeners']})
@@ -206,24 +212,35 @@ class ExtendView extends View {
         
         let endPosition = new THREE.Vector3().copy(info.position)
         let startPosition = this.position.clone();
-		let startQuaternion, endQuaternion, endTarget = null ;
+		let startQuaternion, endQuaternion, endTarget = null, needRot;
         this.restrictPos(endPosition)
-        
+         
 		if(info.target ){
 			endTarget = new THREE.Vector3().copy(info.target)  
-            endQuaternion = math.getQuaFromPosAim(endPosition,endTarget) 
+            endQuaternion = math.getQuaFromPosAim(endPosition,endTarget) //若为垂直,会自动偏向x负的方向
+            let dir = new THREE.Vector3().subVectors(endTarget, endPosition).normalize()
+            //console.log(dir, this.direction)  
+            
+            let view = this.clone();
+            view.direction = dir;
+            console.log(view.yaw, view.pitch,  this.yaw,  this.pitch)
+            
+            
 		}else if(info.quaternion){
             endQuaternion = info.quaternion.clone()
         }
          
         if(endQuaternion){ 
             startQuaternion = new THREE.Quaternion().setFromEuler(this.rotation)
+            needRot = endQuaternion
             /*  const startTarget = this.getPivot();
             let startQuaternion = math.getQuaFromPosAim(startPosition,startTarget) */
-            
+            //console.log('startQuaternion',startQuaternion, this.rotation)
+            //console.log('endQuaternion', endQuaternion, new THREE.Euler().setFromQuaternion(endQuaternion))
         }
         
         
+        
 		if(!info.duration){
 			this.position.copy(endPosition);
             this.restrictPos()
@@ -257,11 +274,13 @@ class ExtendView extends View {
             if(endQuaternion){
                 rotWaitDone = true 
                 transitions.start( (progress, delta )=>{
-                
+                   
                     let quaternion = (new THREE.Quaternion()).copy(startQuaternion) 
-                    lerp.quaternion(quaternion, endQuaternion)(progress),
-                    this.rotation = new THREE.Euler().setFromQuaternion(quaternion)
-                    
+                    lerp.quaternion(quaternion, endQuaternion)(progress)  //在垂直的视角下的角度突变的厉害,这时候可能渐变yaw比较好
+             
+                    //this.rotation = new THREE.Euler().setFromQuaternion(quaternion)
+                    this.quaternion = quaternion
+                     
                     posChange || info.onUpdate && info.onUpdate(progress, delta)  
                     
                 }, info.duration, rotDone , 0, info.Easing ? easing[info.Easing] : easing.easeInOutSine ,null, this.LookTransition, ()=>{
@@ -317,10 +336,8 @@ class ExtendView extends View {
             boundSize.set(1,1)  //避免infinity
         }
         
-        this.setView({ position:endPosition,  duration, 
-            callback:()=>{//done
-                 
-            },
+        this.setView( Object.assign(info,  { position:endPosition,  duration, 
+            
             onUpdate:(progress)=>{ 
                 if(boundSize || endZoom){ 
                     if(boundSize){
@@ -343,8 +360,8 @@ class ExtendView extends View {
             },
             
             Easing:easeName
-        
-        })
+         
+        }))
           
         
     }

+ 828 - 115
src/viewer/NavigationCube.js

@@ -1,119 +1,832 @@
-
+ 
+import {ViewerBase} from "../custom/viewer/viewerBase.js"
 import * as THREE from "../../libs/three.js/build/three.module.js";
+import Viewport from "../custom/viewer/Viewport.js"
+
+import {ExtendView} from "./ExtendView.js"
+import {LineDraw/* , MeshDraw */} from "../custom/utils/DrawUtil.js";
+import {InputHandler} from "../navigation/InputHandlerNew.js";
+
+import {CameraMode  } from "../defines.js"
+
+import SplitScreen from "../custom/utils/SplitScreen.js";
+ 
+ 
+//import {FirstPersonControls} from '../navigation/FirstPersonControlsNew.js'
+ 
+import {OrbitControls} from "../navigation/OrbitControlsNew.js";
+ 
+ 
+ 
+let splitScreen = new SplitScreen()
+
+
+
+
+const Colors = {
+    black : '#161A1A',
+    blue: '#00F',
+    gray: '#878585' ,
+    white:'#ffffff'
+}
+
+
+
+let navCubeViewer
+
+
+class base{
+    constructor(){
+        this.faceDefaultColor = Colors.black//14936556,
+        this.wireframeDefaultColor = 13421772,
+        this.faceHighlightColor = 12255212,
+        this.wireframeHighlightColor = 3330982
+    }
 
-export class NavigationCube extends THREE.Object3D {
-
-	constructor(viewer){
-		super();
-
-		this.viewer = viewer;
-
-		let createPlaneMaterial = (img) => {
-			let material = new THREE.MeshBasicMaterial( {
-				depthTest: true, 
-				depthWrite: true,
-				side: THREE.DoubleSide
-			});
-			new THREE.TextureLoader().load(
-				exports.resourcePath + '/textures/navigation/' + img,
-				function(texture) {
-					texture.anisotropy = viewer.renderer.capabilities.getMaxAnisotropy();
-					material.map = texture;
-					material.needsUpdate = true;
-				});
-			return material;
-		};
-
-		let planeGeometry = new THREE.PlaneGeometry(1, 1);
-
-		this.front = new THREE.Mesh(planeGeometry, createPlaneMaterial('F.png'));
-		this.front.position.y = -0.5;
-		this.front.rotation.x = Math.PI / 2.0;
-		this.front.updateMatrixWorld();
-		this.front.name = "F";
-		this.add(this.front);
-
-		this.back = new THREE.Mesh(planeGeometry, createPlaneMaterial('B.png'));
-		this.back.position.y = 0.5;
-		this.back.rotation.x = Math.PI / 2.0;
-		this.back.updateMatrixWorld();
-		this.back.name = "B";
-		this.add(this.back);
-
-		this.left = new THREE.Mesh(planeGeometry, createPlaneMaterial('L.png'));
-		this.left.position.x = -0.5;
-		this.left.rotation.y = Math.PI / 2.0;
-		this.left.updateMatrixWorld();
-		this.left.name = "L";
-		this.add(this.left);
-
-		this.right = new THREE.Mesh(planeGeometry, createPlaneMaterial('R.png'));
-		this.right.position.x = 0.5;
-		this.right.rotation.y = Math.PI / 2.0;
-		this.right.updateMatrixWorld();
-		this.right.name = "R";
-		this.add(this.right);
-
-		this.bottom = new THREE.Mesh(planeGeometry, createPlaneMaterial('D.png'));
-		this.bottom.position.z = -0.5;
-		this.bottom.updateMatrixWorld();
-		this.bottom.name = "D";
-		this.add(this.bottom);
-
-		this.top = new THREE.Mesh(planeGeometry, createPlaneMaterial('U.png'));
-		this.top.position.z = 0.5;
-		this.top.updateMatrixWorld();
-		this.top.name = "U";
-		this.add(this.top);
-
-		this.width = 150; // in px
-
-		this.camera = new THREE.OrthographicCamera(-1, 1, 1, -1, -1, 1);
-		this.camera.position.copy(new THREE.Vector3(0, 0, 0));
-		this.camera.lookAt(new THREE.Vector3(0, 1, 0));
-		this.camera.updateMatrixWorld();
-		this.camera.rotation.order = "ZXY";
-
-		let onMouseDown = (event) => {
-			if (!this.visible) {
-				return;
-			}
-			
-			this.pickedFace = null;
-			let mouse = new THREE.Vector2();
-			mouse.x = event.clientX - (window.innerWidth - this.width);
-			mouse.y = event.clientY;
-
-			if(mouse.x < 0 || mouse.y > this.width) return;
-
-			mouse.x = (mouse.x / this.width) * 2 - 1;
-			mouse.y = -(mouse.y / this.width) * 2 + 1;
-
-			let raycaster = new THREE.Raycaster();
-			raycaster.setFromCamera(mouse, this.camera);
-			raycaster.ray.origin.sub(this.camera.getWorldDirection(new THREE.Vector3()));
-
-			let intersects = raycaster.intersectObjects(this.children);
-
-			let minDistance = 1000;
-			for (let i = 0; i < intersects.length; i++) {
-				if(intersects[i].distance < minDistance) {
-					this.pickedFace = intersects[i].object.name;
-					minDistance = intersects[i].distance;
-				}
-			}
-			
-			if(this.pickedFace) {
-				this.viewer.setView(this.pickedFace);
-			}
-		};
-
-		this.viewer.renderer.domElement.addEventListener('mousedown', onMouseDown, false);
-	}
-
-	update(rotation) {
-		this.camera.rotation.copy(rotation);
-		this.visible && this.camera.updateMatrixWorld();
-	}
+
+    createMesh(e) {
+        for (var t = new THREE.BufferGeometry, i = e.length - 2, n = new Uint32Array(3 * i), o = 0, s = 1; s <= i; s++)
+            n[o++] = 0,
+            n[o++] = s,
+            n[o++] = s + 1;
+        var r = new THREE.MeshBasicMaterial({
+            color: this.faceDefaultColor,
+            side: THREE.DoubleSide
+        })
+          , a = new Float32Array(3 * e.length);
+        t.setAttribute("position", new THREE.BufferAttribute(a,3).copyVector3sArray(e)),
+        t.setIndex(new THREE.BufferAttribute(n,1));
+        var l = new THREE.Mesh(t,r);
+        return l.componentId = this.componentId,
+        l
+    }
+     
+    createWireframe(e, lineWidth) {
+        /* for (var t = new THREE.LineGeometry, i = [], n = 0; n < e.length; n++) {
+            var o = e[n];
+            i.push(o.x, o.y, o.z)
+        }
+        t.setPositions(i);
+        var s = new THREE.LineMaterial({
+            color: this.wireframeDefaultColor,
+            linewidth: 1
+        });
+        s.resolution.set(160, 160);
+        var r = new THREE.Line2(t,s);
+        return r.componentId = this.componentId,
+        r */
+        
+        let line = LineDraw.createFatLine(e,{
+	        color: Colors.gray , 
+			lineWidth ,
+            viewer:   navCubeViewer,
+            depthTest:true, depthWrite:true,
+            //transparent:true
+	    });
+        line.renderOrder = 3;
+        return line
+        
+    }
+     
+    getMesh() {
+        return this.mesh
+    }
+     
+    getWireframe() {
+        return this.wireframeMesh
+    }
+     
+    transparent(e) {
+        e.material && (e.material.transparent = !0,
+        e.material.opacity = 0)
+    }
+     
+    opaque(e) {
+        e.material && (e.material.transparent = !1,
+        e.material.opacity = 1)
+    }
+     
+    getId() {
+        return this.componentId
+    }
 
 }
+
+
+
+
+
+class Edge extends base{
+    constructor(t, i, n) {
+        super()
+       
+        this.highlightWidth = 3,
+        this.width = 15,
+        this.vertices = t,
+        this.indices = i,
+        this.componentId = n,
+        this.highlightWireframeMesh = null,
+        this.testWireframe = null,
+        this.build() 
+         
+    }
+  
+    build() {
+        var e = this.indices[0]
+          , t = this.indices[1]
+          , i = this.vertices[e]
+          , n = this.vertices[t]
+          , o = i.clone().add(n).multiplyScalar(.5).clone().multiplyScalar(-1)
+          , s = o.clone().normalize()
+          , r = []
+          , a = n.clone().sub(i).normalize()
+          , l = i.clone().add(a.clone().multiplyScalar(20))
+          , h = i.clone().add(a.clone().multiplyScalar(80))
+          , c = [];
+        if (0 !== o.x) {
+            var d = o.x > 0 ? this.width : -this.width;
+            c.push((new THREE.Vector3).setX(d).add(s))
+        }
+        if (0 !== o.y) {
+            var u = o.y > 0 ? this.width : -this.width;
+            c.push((new THREE.Vector3).setY(u).add(s))
+        }
+        if (0 !== o.z) {
+            var g = o.z > 0 ? this.width : -this.width;
+            c.push((new THREE.Vector3).setZ(g).add(s))
+        }
+        2 === c.length && (r.push(l.clone().add(s)),
+        r.push(l.clone().add(c[0])),
+        r.push(h.clone().add(c[0])),
+        r.push(h.clone().add(s)),
+        r.push(h.clone().add(c[1])),
+        r.push(l.clone().add(c[1]))),
+        this.mesh = this.createMesh(r) 
+        this.transparent(this.mesh) 
+        //this.wireframeMesh = this.createWireframe([l, h]),
+        //this.highlightWireframeMesh = this.createHighlightWireframe([l.sub(s), h.sub(s)])
+    }
+     
+    createHighlightWireframe(e) {
+        for (var t = [], i = 0; i < e.length; i++) {
+            var n = e[i];
+            t.push(n.x, n.y, n.z)
+        }
+        var o = new THREE.LineGeometry;
+        o.setPositions(t);
+        var s = new THREE.LineMaterial({
+            color: this.wireframeHighlightColor,
+            linewidth: this.highlightWidth,
+            dashed: !1
+        });
+        s.resolution.set(160, 160);
+        var r = new THREE.Line2(o,s);
+        return r.computeLineDistances(),
+        r.scale.set(1, 1, 1),
+        r.visible = !1,
+        r.renderOrder = 100,
+        r
+    }
+     
+    getTestWireframe() {
+        return this.testWireframe
+    }
+     
+    getHighlightWireframeMesh() {
+        return this.highlightWireframeMesh
+    }
+     
+    highlight() {
+        this.highlightWireframeMesh.visible = !0,
+        this.highlightWireframeMesh.renderOrder = 100
+    }
+     
+    cancelHighlight() {
+        this.highlightWireframeMesh.visible = !1
+    }
+    
+} 
+
+
+
+
+
+
+
+
+
+class Corner extends base{
+    constructor(t, i) {
+        super()
+        this.length = 20,
+        this.vertex = t,
+        this.cornerFace = null,
+        this.cornerWireframe = null,
+        this.componentId = i,
+        this.cornerVertices = null,
+        this.build() 
+        
+    }
+    
+    
+    build() {
+        var e = []
+          , t = this.vertex.clone()
+          , i = t.clone().multiplyScalar(-1);
+        e.push(t);
+        var n = this.vertex.clone()
+          , o = i.x > 0 ? this.length : -this.length;
+        n.x += o,
+        e.push(n);
+        var s = this.vertex.clone()
+          , r = i.y > 0 ? this.length : -this.length;
+        s.y += r,
+        e.push(s);
+        var a = this.vertex.clone()
+          , l = i.z > 0 ? this.length : -this.length;
+        a.z += l,
+        e.push(a),
+        this.cornerVertices = e 
+        this.mesh = this.createMesh([n, s, a]) 
+         this.wireframeMesh = this.createWireframe([n, s, a, n], 2),
+        this.buildCornerFace() 
+         this.buildCornerWireframe()
+    }
+    
+    highlight() {
+        this.wireframeMesh.material.color.setHex(this.wireframeHighlightColor),
+        this.wireframeMesh.renderOrder = 100,
+        this.mesh.material.color.setHex(this.faceHighlightColor),
+        this.cornerFace.material.color.setHex(this.faceHighlightColor),
+        this.cornerFace.material.transparent = !0,
+        this.cornerFace.material.opacity = .5,
+        this.cornerWireframe.material.color.setHex(this.wireframeHighlightColor),
+        this.cornerWireframe.visible = !0
+    }
+   
+    cancelHighlight() {
+        this.wireframeMesh.material.color.setHex(this.wireframeDefaultColor),
+        this.wireframeMesh.renderOrder = 0,
+        this.mesh.material.color.setHex(this.faceDefaultColor),
+        this.transparent(this.cornerFace),
+        this.cornerWireframe.visible = !1
+    }
+  
+    buildCornerFace() {
+        if (!this.cornerFace) {
+            var e = this.cornerVertices;
+            e.push(e[1]),
+            this.cornerFace = this.createMesh(e),
+            this.transparent(this.cornerFace)
+        }
+    }
+    
+    getCornerFace() {
+        return this.cornerFace
+    }
+    
+    getCornerWireframe() {
+        return this.cornerWireframe
+    }
+   
+    buildCornerWireframe() {
+        if (!this.cornerWireframe) {
+            for (var e = [], t = 1; t < this.cornerVertices.length; t++) {
+                var i = this.cornerVertices[0]
+                  , n = this.cornerVertices[t];
+                e.push(i, n)
+            }
+            this.cornerWireframe = this.createWireframe(e),
+            this.cornerWireframe.visible = !1
+        }
+    }
+    
+    
+} 
+
+
+
+
+
+
+class Face extends base{
+    constructor(t, i, n, o){
+        
+        super()
+        
+        this.length = 60 
+        this.vertices = t,
+        this.indices = i,
+        this.componentId = n,
+        this.vertexUvs = null,
+        this.texture = o,
+        this.highlightMesh = null,
+        this.wireframeMesh = null,
+        this.vertexUvs = [],
+        this.vertexUvs.push(new THREE.Vector2(0,.2)),
+        this.vertexUvs.push(new THREE.Vector2(0,.8)),
+        this.vertexUvs.push(new THREE.Vector2(.2,1)),
+        this.vertexUvs.push(new THREE.Vector2(.8,1)),
+        this.vertexUvs.push(new THREE.Vector2(1,.8)),
+        this.vertexUvs.push(new THREE.Vector2(1,.2)),
+        this.vertexUvs.push(new THREE.Vector2(.8,0)),
+        this.vertexUvs.push(new THREE.Vector2(.2,0)),
+        this.build()
+        
+    }
+    
+    build() {
+        for (var e = [], t = null, i = null, n = 0, o = this.indices.length; n < o; n++) {
+            var s = this.indices[n]
+              , r = this.indices[n + 1];
+            t = this.vertices[s],
+            i = this.vertices[r],
+            n === o - 1 && (i = this.vertices[this.indices[0]]);
+            var a = i.clone().sub(t).normalize()
+              , l = t.clone().add(i).multiplyScalar(.5);
+            e.push(l.clone().sub(a.clone().multiplyScalar(this.length / 2))),
+            e.push(l.clone().add(a.clone().multiplyScalar(this.length / 2)))
+        }
+        this.createTexturedMesh(e);
+        for (var h = new THREE.Box3, c = 0; c < this.indices.length; c++) {
+            var d = this.indices[c];
+            h.expandByPoint(this.vertices[d])
+        }
+        for (var u = h.getCenter(new THREE.Vector3).normalize(), g = [], p = 0; p < e.length; p++) {
+            var m = e[p];
+            g.push(m.clone().add(u))
+        }
+        this.highlightMesh = this.createMesh(g) 
+        this.highlightMesh.visible = !1 
+        this.highlightMesh.isHighlightMesh = !0 
+        g.push(g[0]) 
+        this.wireframeMesh = this.createWireframe(g, 1)
+    }
+     
+    highlight() {
+        this.highlightMesh.visible = !0 
+        this.highlightMesh.material.color.setHex(this.faceHighlightColor) 
+        this.highlightMesh.material.transparent = !0 
+        this.highlightMesh.material.opacity = .5 
+        //this.wireframeMesh.material.color.setHex(this.wireframeHighlightColor)
+    }
+    
+    cancelHighlight() {
+        this.highlightMesh.visible = !1 
+        //this.wireframeMesh.material.color.setHex(this.wireframeDefaultColor)
+    }
+     
+    createTexturedMesh(e) {
+        for (var t = e.length - 2, i = new Uint32Array(3 * t), n = 0, o = 1; o <= t; o++)
+            i[n++] = 0,
+            i[n++] = o,
+            i[n++] = o + 1;
+        var s = new THREE.BufferGeometry
+          , r = new Float32Array(3 * e.length)
+          , a = new Float32Array(2 * this.vertexUvs.length);
+        s.setAttribute("position", new THREE.BufferAttribute(r,3).copyVector3sArray(e)),
+        s.setAttribute("uv", new THREE.BufferAttribute(a,2).copyVector2sArray(this.vertexUvs)),
+        s.setIndex(new THREE.BufferAttribute(i,1));
+       
+        
+        var l = new THREE.ShaderMaterial({ 
+            side: THREE.DoubleSide,
+            transparent: !1, 
+            uniforms:{
+                faceColor: {type:'v3',   value:  new THREE.Color(Colors.black)  } , 
+                textColor: {type:'v3',   value:  new THREE.Color(Colors.white)  } , 
+                map: {type: 't',    value: this.texture },
+            },
+            vertexShader:`
+                varying vec2 vUv;
+                void main() { 
+                    vUv = uv;
+                    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
+                }`,
+            
+            
+             fragmentShader:` 
+                varying vec2 vUv; 
+                uniform vec3 faceColor;
+                uniform vec3 textColor;
+                uniform sampler2D map;
+                void main() {
+                    //从图上实测
+                    const float mapFaceColorR = 0.85; 
+                    const float mapTextColotR = 0.45; 
+                     
+                    
+                    vec4 texColor = texture2D(map, vUv);  
+                    if(texColor.r > mapFaceColorR){
+                        gl_FragColor = vec4(faceColor, texColor.a);
+                    }else if(texColor.r<mapTextColotR){
+                        gl_FragColor = vec4(textColor, texColor.a);
+                    }else{//抗锯齿 过渡
+                        float faceRatio = (texColor.r - mapTextColotR) / (mapFaceColorR - mapTextColotR);
+                        gl_FragColor = vec4( mix(textColor, faceColor, faceRatio),  texColor.a); 
+                    }
+                }
+            ` 
+        }); 
+        
+        
+        this.mesh = new THREE.Mesh(s,l),
+        this.mesh.componentId = this.componentId
+    }
+    
+    getHighlightMesh() {
+        return this.highlightMesh
+    }
+     
+    buildVertexUvs(e) {
+        var t = []
+          , i = (new THREE.Box3).setFromPoints(e)
+          , n = i.min
+          , o = new THREE.Vector2;
+        i.getSize(o);
+        for (var s = 0 == o.x ? "x" : 0 == o.y ? "y" : "z", r = 0; r < e.length; r++) {
+            var a = e[r]
+              , l = (o.x + o.y + o.z) / 2
+              , h = a.clone().sub(n).multiplyScalar(1 / l)
+              , c = new THREE.Vector2(h.x,h.y);
+            "x" == s ? c = new THREE.Vector2(h.y,h.z) : "y" == s && (c = new THREE.Vector2(h.x,h.z)),
+            t.push(c)
+        }
+        return t
+    }
+     
+} 
+
+
+
+
+
+
+
+
+class NavigationCube{
+    constructor(scene, length){
+        this.scene = scene 
+        this.length = length
+        this.initialize() 
+        
+        /*this.callback = t 
+        this.buildEdges()   */
+        this.buildCorners()
+        this.buildFaces() 
+    }
+    
+    
+    initialize(){
+        this.enumViewMode = {
+            "2673": "Top",      //数字是面的faceIndex组合
+            "4015": "Bottom",
+            "0231": "Front",
+            "5764": "Back",
+            "1375": "Right",
+            "4620": "Left",
+            3: "RoofSouthEast",
+            2: "RoofSouthWest",
+            7: "RoofNorthEast",
+            6: "RoofNorthWest",
+            1: "BottomSouthEast",
+            0: "BottomSouthWest",
+            4: "BottomNorthWest",
+            5: "BottomNorthEast",
+            32: "RoofFront",
+            76: "RoofBack",
+            37: "RoofRight",
+            26: "RoofLeft",
+            "01": "BottomFront",
+            45: "BottomBack",
+            15: "BottomRight",
+            "04": "BottomLeft",
+            13: "SouthEast",
+            20: "SouthWest",
+            57: "NorthEast",
+            64: "NorthWest"
+        }  
+        this.vertices = [],
+        this.vertexIds = [],
+        this.edgeIds = [],
+        this.edgeIndices = [],
+        this.faceIds = [],
+        this.faceIndices = [],
+        this.componentList = [] 
+ 
+        var e = this.length;
+        //立方体八个点
+        this.vertices.push(new THREE.Vector3(-e / 2,-e / 2,e / 2)),
+        this.vertices.push(new THREE.Vector3(e / 2,-e / 2,e / 2)),
+        this.vertices.push(new THREE.Vector3(-e / 2,e / 2,e / 2)),
+        this.vertices.push(new THREE.Vector3(e / 2,e / 2,e / 2)),
+        this.vertices.push(new THREE.Vector3(-e / 2,-e / 2,-e / 2)),
+        this.vertices.push(new THREE.Vector3(e / 2,-e / 2,-e / 2)),
+        this.vertices.push(new THREE.Vector3(-e / 2,e / 2,-e / 2)),
+        this.vertices.push(new THREE.Vector3(e / 2,e / 2,-e / 2));
+        for (var t = 0; t < 8; t++)
+            this.vertexIds.push(t + ""); 
+        //12条边
+        this.edgeIndices.push([0, 1], [1, 3], [3, 2], [2, 0]),
+        this.edgeIndices.push([0, 4], [1, 5], [2, 6], [3, 7]),
+        this.edgeIndices.push([4, 5], [5, 7], [7, 6], [6, 4]);
+        for (t = 0; t < 12; t++) {
+            var i = this.edgeIndices[t];
+            this.edgeIds.push(i[0] + "" + i[1])
+        }
+        
+        //6个面,每个面2个三角形
+        this.faceIndices.push([0, 2, 3, 1]),
+        this.faceIndices.push([4, 0, 1, 5]),
+        this.faceIndices.push([4, 6, 2, 0]),
+        this.faceIndices.push([2, 6, 7, 3]),
+        this.faceIndices.push([1, 3, 7, 5]),
+        this.faceIndices.push([5, 7, 6, 4]);
+        
+        for (t = 0; t < 6; t++) {
+            var n = this.faceIndices[t];
+            this.faceIds.push(n[0] + "" + n[1] + n[2] + n[3])
+        }
+    }
+     
+    buildFaces() {
+        const directions = {
+            Top : new THREE.Vector3(0,0,-1),
+            Bottom : new THREE.Vector3(0,0,1),
+            Left : new THREE.Vector3(1,0,0),
+            Right : new THREE.Vector3(-1,0,0),
+            Front : new THREE.Vector3(0,1,0),
+            Back : new THREE.Vector3(0,-1,0),
+        }
+        
+        let texturesLoaded = 0
+        let create = (n)=>{
+            let name = this.enumViewMode[this.faceIds[n]]
+            var url = Potree.resourcePath+'/textures/navigation/' + name + ".png"
+              , r = new THREE.TextureLoader;
+            r.setCrossOrigin("anonymous"); 
+            r.load(url, (tex)=> {
+                var face = new Face(e,t[n], this.faceIds[n], tex);
+                this.componentList.push(face) 
+                let faceMesh = face.getMesh()
+                this.scene.add(faceMesh) 
+                this.scene.add(face.getWireframe()) 
+                /* this.scene.add(face.getHighlightMesh())  */
+                //6 == ++texturesLoaded && a.callback && a.callback()
+                
+                //不过平板无hover事件
+                faceMesh.addEventListener('mouseover', (e)=>{
+                    if(this.changingView)return
+                    faceMesh.material.uniforms.faceColor.value.set(Colors.blue)
+                    //console.log('变', name)
+                    navCubeViewer.dispatchEvent('content_changed')
+                });
+                faceMesh.addEventListener('mouseleave', (e)=>{
+                    if(this.changingView)return
+                    faceMesh.material.uniforms.faceColor.value.set(Colors.black)
+                    //console.log('回', name)
+                    navCubeViewer.dispatchEvent('content_changed')
+                });
+                
+                faceMesh.addEventListener('click', (e)=>{
+                    this.changingView = true 
+                    faceMesh.material.uniforms.faceColor.value.set(Colors.blue) 
+                    /* 
+                    this.changingView = true 
+                    let viewStart = viewer.scene.view.clone();   
+                    viewer["set"+name+'View']() 
+                    let viewEnd = viewer.scene.view.clone(); 
+                    viewer.scene.view.copy(viewStart)  //先变回来,以渐变
+                     
+                    let duration = 4000
+                    viewer.scene.view.setView({
+                        position: viewEnd.position ,
+                        quaternion:new THREE.Quaternion().setFromEuler(viewEnd.rotation),
+                        duration,
+                        callback: ()=>{
+                            this.changingView = false
+                            faceMesh.material.uniforms.faceColor.value.set(Colors.black)
+                            console.log('回2', name)
+                            navCubeViewer.dispatchEvent('content_changed')
+                        },onUpdate: (e)=>{ 
+                             console.log(e, viewer.scene.view.position.toArray(),  viewer.scene.view.rotation.toArray())
+                        }                        
+                    }) */
+                    if(viewer.mainViewport.camera != viewer.scene.cameraO){
+                        viewer.scene.cameraO.position.copy(viewer.mainViewport.camera.position)
+                        viewer.scene.cameraO.quaternion.copy(viewer.mainViewport.camera.quaternion)
+                        viewer.mainViewport.camera = viewer.scene.cameraO
+                        viewer.setCameraMode(CameraMode.ORTHOGRAPHIC)
+                         
+                        
+                    }
+                    
+                    viewer.focusOnObject(viewer.bound, 'boundingBox', 1000, {dir:directions[name].clone()}).promise.done(()=>{
+                        this.changingView = false
+                        faceMesh.material.uniforms.faceColor.value.set(Colors.black)
+                        //console.log('回2', name)
+                        navCubeViewer.dispatchEvent('content_changed')
+                    })
+                    
+                }); 
+                 
+            })
+        }  
+        
+         
+        for (var e = this.vertices, t = this.faceIndices,   s = 0; s < 6; s++){
+           create(s)
+        }
+    }
+      
+
+
+
+
+    buildEdges() {
+        for (var e = this.vertices, t = this.edgeIndices, i = this.edgeIds, n = 0; n < 12; n++) {
+            var o = new Edge(e,t[n],i[n]);
+            this.componentList.push(o),
+            this.scene.add(o.getMesh()),
+            this.scene.add(o.getWireframe()),
+            this.scene.add(o.getHighlightWireframeMesh())
+        }
+    }
+
+    buildCorners() {
+        for (var e = this.vertices, t = this.vertexIds, i = 0; i < 8; i++) {
+            var n = new Corner(e[i],t[i]);
+            this.componentList.push(n) 
+            this.scene.add(n.getMesh())  
+            this.scene.add(n.getWireframe()),
+            this.scene.add(n.getCornerFace()) 
+            this.scene.add(n.getCornerWireframe())
+        }
+    }
+     
+    getComponent(e) {
+        for (var t = 0; t < this.componentList.length; t++) {
+            var i = this.componentList[t];
+            if (i.getId() == e)
+                return i
+        }
+        return null
+    }
+    
+    
+    /* 
+    getMeshes() {
+        for (var e = [], t = this.scene.children, i = 0; i < t.length; i++) {
+            var n = t[i];
+            "Mesh" === n.type && !0 !== n.isHighlightMesh && e.push(n)
+        }
+        return e
+    }
+    
+    destroy() {
+        this.scene = null,
+        this.vertices = null,
+        this.vertexIds = null,
+        this.edgeIds = null,
+        this.edgeIndices = null,
+        this.faceIds = null,
+        this.faceIndices = null,
+        this.componentList = null,
+        this.enumViewMode = null
+    }
+    , */
+    
+    
+}
+    
+    
+    
+    
+    
+    
+class NavCubeViewer extends ViewerBase{
+   constructor(domElement, listenViewport){
+        super(domElement,  {name:'navCube', antialias:true/* , preserveDrawingBuffer:true */} )
+        
+        navCubeViewer = this 
+        this.scene = new THREE.Scene 
+        this.scene.rotation.x = Math.PI/2  //Yup->Zup 
+         
+        this.listenViewport = listenViewport
+        
+        let w = 200
+        this.camera = new THREE.OrthographicCamera(-w/2,w/2,w/2,-w/2 , 1, w*4);  
+        this.camera.zoom = (domElement.clientWidth || 300) / w * 1.267//zoom越大视野越小
+        this.camera.updateProjectionMatrix()
+        this.view = new ExtendView();
+        /* this.view.position.set(0,0,0);
+        this.view.lookAt(0,0,0) */
+        this.viewports = [new Viewport( this.view, this.camera, {
+            left:0, bottom:0, width:1, height: 1, name:'navCube' 
+        }) ]
+        
+        this.cube = new NavigationCube(this.scene,  w/2 )
+        
+         
+        
+        viewer.addEventListener('camera_changed', e => {
+            if (e.viewport == listenViewport && (/* e.changeInfo.positionChanged ||  */e.changeInfo.quaternionChanged)) {
+                 this.updateCamera()
+            } 
+        })
+        
+        
+        this.controls = new OrbitControls(this, this.viewports[0]);
+        this.controls.setEnable(true)
+        this.controls.setScene(true)
+        this.view.radius = this.cube.length * 3//相机距离
+        
+        
+        //事件 
+        this.inputHandler = new InputHandler(this, this.scene);
+        this.inputHandler.name = 'navCube'
+        //this.inputHandler.addInputListener(this.controls);
+        this.inputHandler.registerInteractiveScene(this.scene);//interactiveScenes 
+        this.viewports[0].interactiveScenes = this.inputHandler.interactiveScenes;//供viewer的inputHandler使用
+         
+        
+        viewer.addEventListener('allLoaded',()=>{
+            let viewportProps = [{
+                left:0, bottom:0,
+                width:1, height:1,
+                name : "MainView", 
+                //axis:["y","z"],
+                //direction : new THREE.Vector3(1,0,0), 
+                active: true,
+                //相机位置在x轴负向  右下角屏
+                viewContainsPoints:[new THREE.Vector3(0,0,0)],
+                margin:{x:300, y:250} ,
+            } ]
+            splitScreen.splitStart(viewportProps)
+        })
+        
+        
+    }
+   
+    render(){
+        this.renderer.render(this.scene, this.camera)
+    }
+
+    update(delta){     
+        this.updateScreenSize() 
+        this.controls.update(delta)
+        this.view.applyToCamera(this.camera) 
+        
+        let changed = this.cameraChanged()
+        if(changed || this.needRender){
+            this.needRender = false
+            this.render()
+            this.applyToMainView()
+        }
+    }
+    
+    updateCamera(){  
+        let view = this.listenViewport.view
+        this.view.quaternion = view.quaternion   //this.view.rotation = view.rotation 
+        var dir = view.direction;  //相机朝向
+        this.view.position.copy(dir.multiplyScalar(this.view.radius).negate())  //相机绕着指南针中心(000)转动
+          
+    }
+    
+    
+    applyToMainView(){
+        let view = this.listenViewport.view
+        view.quaternion = this.view.quaternion 
+    }
+    
+    pushHomeBtn(){
+        if(viewer.mainViewport.camera == viewer.scene.cameraO){
+            //viewer.scene.cameraP.position.copy(viewer.mainViewport.camera.position)
+            //viewer.scene.cameraP.quaternion.copy(viewer.mainViewport.camera.quaternion)
+            viewer.mainViewport.camera = viewer.scene.cameraP
+            viewer.setCameraMode(CameraMode.PERSPECTIVE)
+            
+            //假设保持到目前中心的视角范围不变
+            let view = viewer.mainViewport.view
+            splitScreen.setShiftTarget(viewer.mainViewport, viewer.bound.center)
+            viewer.mainViewport.targetPlane.setFromNormalAndCoplanarPoint( view.direction.clone(), viewer.bound.center )  
+            viewer.mainViewport.targetPlane.projectPoint(view.position, viewer.mainViewport.shiftTarget )  
+             
+            let halfHeight = viewer.scene.cameraO.top/viewer.scene.cameraO.zoom 
+            let dis = halfHeight / Math.tan( THREE.Math.degToRad(viewer.scene.cameraP.fov/2)) 
+            
+            view.position.copy(viewer.mainViewport.shiftTarget).sub(view.direction.clone().multiplyScalar(dis)); 
+              
+        }
+    }  
+
+
+    rotateSideCamera(angle){
+        splitScreen.rotateSideCamera(viewer.mainViewport,angle)
+    }
+    
+} 
+
+
+
+export {NavCubeViewer}

+ 5 - 3
src/viewer/View.js

@@ -41,10 +41,12 @@ export class View{//base
 	}
 
 	set direction (dir) {
-
-		//if(dir.x === dir.y){
+        dir = dir.clone().normalize()//add
+        
 		if(dir.x === 0 && dir.y === 0){
-			this.pitch = Math.PI / 2 * Math.sign(dir.z);
+			this.pitch = Math.PI / 2 * Math.sign(dir.z); 
+            this.yaw = 0   //add:还是要指定一下, 否则不统一
+            
 		}else{
 			let yaw = Math.atan2(dir.y, dir.x) - Math.PI / 2;
 			let pitch = Math.atan2(dir.z, Math.sqrt(dir.x * dir.x + dir.y * dir.y));