import {ExtendView} from "../../viewer/ExtendView.js"; import Viewport from "../viewer/Viewport.js"; import * as THREE from "../../../libs/three.js/build/three.module.js"; class SplitScreen extends THREE.EventDispatcher{ constructor (args = {}) { super(); } /* viewport.targetPlane // bound中心点处的plane,方向和view一致 viewport.shiftTarget // camera的位置project在targetPlane上的位置 这两个参数的主要目的是为了getPosOutOfModel,以及rotateSideCamera时保持相对位置 */ splitStart(cameraProps){ this.splited = true let viewports = [] let subViewports = [viewer.mainViewport] if(viewer.mapViewer){ subViewports.push(viewer.mapViewer.viewports[0]) } let length = cameraProps.length for(let i=0;ie.name == (prop.name2||prop.name)) if(v){ viewport = v viewport.left = prop.left; viewport.bottom = prop.bottom; viewport.width = prop.width; viewport.height = prop.height; } if(!viewport){ let view = new ExtendView() if(prop.limitBound)view.limitBound = prop.limitBound prop.direction && (view.direction = prop.direction) viewport = new Viewport(view , this.getOrthoCamera(), prop ) if(prop.viewContainsPoints)viewport.viewContainsPoints = prop.viewContainsPoints //viewport.unableDepth = true //depthBasicMaterial等在此viewport中不开启depth } if(viewport.camera.type == 'OrthographicCamera' ){ viewport.targetPlane = new THREE.Plane() viewport.shiftTarget = new THREE.Vector3 //project在targetPlane上的位置 } viewport.fitMargin = prop.margin viewports.push(viewport) } viewer.viewports = viewports; viewer.updateScreenSize({forceUpdateSize:true}) viewports.forEach(viewport=>{ if(viewport.name == 'MainView')return this.viewportFitBound(viewport, viewer.bound.boundingBox , viewer.bound.center , 0, viewport.fitMargin) }) return viewports } unSplit(){ this.splited = false this.unfocusViewport() viewer.inputHandler.hoverViewport = null //清空 viewer.viewports = [viewer.mainViewport] viewer.mainViewport.width = 1; viewer.mainViewport.height = 1; viewer.mainViewport.left = 0 viewer.mainViewport.bottom = 0; viewer.updateScreenSize({forceUpdateSize:true}) } viewportFitBound(viewport, bound, center, duration=0, margin){ let view = viewport.view let info = {bound} let {boundSize, boundCenter} = this.getViewBound(viewport, bound ) //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) info.margin = margin || {x:30, y:30} view.moveOrthoCamera(viewport, info , duration ) } getViewBound(viewport, boundingBox){ if(boundingBox){ boundSize = boundingBox.getSize(new THREE.Vector3) center = boundingBox.getCenter(new THREE.Vector3) }else{ var {boundSize, center, boundingBox} = viewer.bound } let containsPoints = [] this.focusCenter && containsPoints.push(this.focusCenter) viewport.viewContainsPoints && containsPoints.push(...viewport.viewContainsPoints) if(containsPoints.length){//视野范围内必须要包含的点,直接算入模型区域。这时候得到的boundCenter和模型中心不重合 boundingBox = boundingBox.clone() containsPoints.forEach(point=>{ boundingBox.expandByPoint(point) }) boundSize = boundingBox.getSize(new THREE.Vector3) center = boundingBox.getCenter(new THREE.Vector3) } return {boundSize, boundCenter:center } } getPosOutOfModel(viewport, boundSize){ //let {boundSize, center} = viewer.bound boundSize = boundSize || this.getViewBound(viewport).boundSize let expand = 10; let radius = boundSize.length() * 2 let position = viewport.shiftTarget.clone().sub(viewport.view.direction.clone().multiplyScalar(radius + expand)) return position } updateCameraOutOfModel(){//因为移动模型导致模型超出相机外,所以更新位置 viewer.viewports.forEach((viewport, i )=>{ if(viewport.camera.isOrthographicCamera){ //or if(viewport.targetPlane) let {boundSize, boundCenter} = this.getViewBound(viewport) /* 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) } }) } 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) //找到平移向量 let vec = new THREE.Vector3().subVectors(center, viewport.shiftTarget)//相对于中心的偏移值,旋转后偏移值也旋转 //旋转 var rotMatrix = new THREE.Matrix4().makeRotationAxis(new THREE.Vector3(0,0,1), angle) viewport.view.direction = viewport.view.direction.applyMatrix4(rotMatrix) vec.applyMatrix4(rotMatrix) viewport.shiftTarget.subVectors(center,vec) //新的 viewport.view.position = this.getPosOutOfModel(viewport, boundSize) } getOrthoCamera(){ let camera = new THREE.OrthographicCamera(-100, 100, 100, 100, 0.01, 10000) camera.up.set(0,0,1) return camera } focusOnViewport(name){//全屏 viewer.viewports.forEach((viewport, i )=>{ if(viewport.name == name){ this.focusInfo = { name, left : viewport.left, bottom : viewport.bottom, height : viewport.height, width : viewport.width } viewport.left = 0; viewport.bottom = 0; viewport.height = 1; viewport.width = 1 }else{ viewport.active = false } }) viewer.updateScreenSize({forceUpdateSize:true}) } unfocusViewport(){ if(!this.focusInfo)return viewer.viewports.forEach((viewport, i )=>{ if(this.focusInfo.name == viewport.name){//全屏的恢复 viewport.left = this.focusInfo.left; viewport.bottom = this.focusInfo.bottom; viewport.height = this.focusInfo.height; viewport.width = this.focusInfo.width; } viewport.active = true }) viewer.updateScreenSize({forceUpdateSize:true}) this.focusInfo = null } } export default SplitScreen