123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466 |
- import * as THREE from "../../libs/three.js/build/three.module.js";
- import {transitions, easing, lerp} from '../custom/utils/transitions.js'
- import math from '../custom/utils/math.js'
- import Common from '../custom/utils/Common.js'
- import {View} from './View.js'
- let sid = 0
-
- class ExtendView extends View {
- constructor () {
- super()
-
-
- this.yaw = 0 //Math.PI / 4; // = 4dkk lon + 90
- this._pitch = 0 //-Math.PI / 4; //上下旋转 = 4dkk lat
-
- this.sid = sid++
- this.LookTransition = 'LookTransition'+this.sid
- this.FlyTransition = 'FlyTransition'+this.sid
- }
- //add------
- applyToCamera(camera){
- camera.position.copy(this.position);
- camera.rotation.copy(this.rotation)
-
-
- camera.updateMatrix();
- camera.updateMatrixWorld();
- //camera.matrixWorldInverse.copy(camera.matrixWorld).invert();
-
-
- }
-
- get rotation(){
- var rotation = new THREE.Euler;
- rotation.order = "ZXY";
- rotation.x = Math.PI / 2 + this.pitch;
- rotation.z = this.yaw;
- return 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) //注意如果得到的dir.x==dir.y==0, yaw不会变为0, 导致算的quaternion和q不一致
- }
-
- copy(a){
- Common.CopyClassObject(this, a, {ignoreList: ['_listeners']})
- }
-
- clone () {
- return Common.CloneClassObject(this, {ignoreList: ['_listeners']})
- }
-
- //----------
-
-
- setCubeView(dir) {
-
- switch(dir) {
- case "front":
- this.yaw = 0;
- this.pitch = 0;
- break;
- case "back":
- this.yaw = Math.PI;
- this.pitch = 0;
- break;
- case "left":
- this.yaw = -Math.PI / 2;
- this.pitch = 0;
- break;
- case "right":
- this.yaw = Math.PI / 2;
- this.pitch = 0;
- break;
- case "top":
- this.yaw = 0;
- this.pitch = -Math.PI / 2;
- break;
- case "bottom":
- this.yaw = -Math.PI;
- this.pitch = Math.PI / 2;
- break;
- }
- }
-
-
-
- /* pan (x, y) {
- let dir = new THREE.Vector3(0, 1, 0);
- dir.applyAxisAngle(new THREE.Vector3(1, 0, 0), this.pitch);
- dir.applyAxisAngle(new THREE.Vector3(0, 0, 1), this.yaw);
- // let side = new THREE.Vector3(1, 0, 0);
- // side.applyAxisAngle(new THREE.Vector3(0, 0, 1), this.yaw);
- let side = this.getSide();
- let up = side.clone().cross(dir);
- let pan = side.multiplyScalar(x).add(up.multiplyScalar(y));
- this.position = this.position.add(pan);
- // this.target = this.target.add(pan);
- } */
- pan (x, y) { //发现pan其实就是translate
- this.translate(x, 0, y)
- }
- translate (x, y, z, forceHorizon ) {
- //相机方向
- let dir = new THREE.Vector3(0, 1, 0);
- dir.applyAxisAngle(new THREE.Vector3(1, 0, 0), forceHorizon ? 0 : this.pitch); //上下角度
- dir.applyAxisAngle(new THREE.Vector3(0, 0, 1), this.yaw);//水平角度
- let side = new THREE.Vector3(1, 0, 0);
- side.applyAxisAngle(new THREE.Vector3(0, 0, 1), this.yaw); //垂直于相机当前水平朝向的 左右方向
- let up = side.clone().cross(dir); //垂直于相机当前水平朝向的 向上方向
- let t = side.multiplyScalar(x) //x影响 左右分量
- .add(dir.multiplyScalar(y)) //y影响 前后分量
- .add(up.multiplyScalar(z)); //z影响 上下分量
-
-
-
- this.position = this.position.add(t);
-
- if((!math.closeTo(x, 0, 1e-4) || !math.closeTo(y, 0, 1e-4) || !math.closeTo(z, 0, 1e-4)) && Potree.settings.displayMode != 'showPanos'){
- this.cancelFlying('pos')
- }
-
- this.restrictPos()
- }
- translateWorld (x, y, z) {
- super.translateWorld(x, y, z)
-
- if((!math.closeTo(x, 0, 1e-4) || !math.closeTo(y, 0, 1e-4) || !math.closeTo(z, 0, 1e-4)) && Potree.settings.displayMode != 'showPanos'){
- this.cancelFlying('pos')
- }
-
- this.restrictPos()
- }
- restrictPos(position){//add
- if(this.limitBound){
- (position || this.position).clamp(this.limitBound.min, this.limitBound.max)
- }
- }
-
- isFlying(type='all'){
- let a = transitions.getById(this.FlyTransition).length > 0
- let b = transitions.getById(this.LookTransition).length > 0
-
- return type == 'pos' ? a : type == 'rotate' ? b : (a || b)
- }
-
- cancelFlying(type='all', dealCancel=true){//外界只能通过这个来cancel
- type == 'pos' ? transitions.cancelById(this.FlyTransition, dealCancel )
- : type == 'rotate' ? transitions.cancelById(this.LookTransition, dealCancel )
- : (transitions.cancelById(this.FlyTransition, dealCancel ), transitions.cancelById(this.LookTransition, dealCancel ))
- //console.log('cancelFlying ' , this.sid, type)
- }
-
-
-
-
- setView( info = {}){
- // position, target, duration = 0, callback = null, onUpdate = null, Easing='', cancelFun
- this.cancelFlying()
- let posWaitDone, rotWaitDone , dir
-
- let posDone = ()=>{
- rotWaitDone || done()
- posWaitDone = false
- }
- let rotDone = ()=>{
- if(endTarget){
- this.lookAt(endTarget); //compute radius for orbitcontrol
- }else if(endQuaternion){
- this.rotation = new THREE.Euler().setFromQuaternion(endQuaternion)
- }else if(endYaw != void 0){
- this.yaw = endYaw, this.pitch = endPitch
- }
- //if(dir.x == 0 && dir.y == 0)this.yaw = 0 //统一一下 朝上的话是正的。朝下的一般不是0,会保留一个接近0的小数所以不用管
-
- posWaitDone || done()
- rotWaitDone = false
- }
-
- let done = ()=>{ //一定要旋转和位移都结束了才能执行
-
- let f = ()=>{
- this.position.copy(endPosition) //因为延时1后control的update会导致位置改变
- info.callback && info.callback()
- this.dispatchEvent('flyingDone')
- }
- if(info.duration){
- setTimeout(f,1)//延迟是为了使isFlying先为false
- }else{
- f() //有的需要迅速执行回调
- }
-
- }
-
- let endPosition = new THREE.Vector3().copy(info.position)
- let startPosition = this.position.clone();
- let startQuaternion, endQuaternion, endTarget = null,
- endYaw, startYaw, endPitch, startPitch ;
-
-
- this.restrictPos(endPosition)
-
-
- if(info.endYaw != void 0) {
- startPitch = this.pitch
- endPitch = info.endPitch;
- startYaw = this.yaw
- endYaw = info.endYaw
- if(Math.abs(startYaw - endYaw)>Math.PI){//如果差距大于半个圆,就要反个方向转(把大的那个数字减去360度)
- startYaw > endYaw ? (startYaw -= Math.PI*2) : (endYaw -= Math.PI*2)
- }
-
- }else if(info.target ){
- endTarget = new THREE.Vector3().copy(info.target)
- endQuaternion = math.getQuaFromPosAim(endPosition,endTarget) //若为垂直,会自动偏向x负的方向
- dir = new THREE.Vector3().subVectors(endTarget, endPosition).normalize()
- //console.log(dir, this.direction)
- }else if(info.quaternion){
- endQuaternion = info.quaternion.clone()
- }
-
- if(endQuaternion){
- startQuaternion = this.quaternion
- }
-
-
-
- if(!info.duration){
- this.position.copy(endPosition);
- this.restrictPos()
- posWaitDone = true, rotWaitDone = true
- info.onUpdate && info.onUpdate(1)
- posDone()
- rotDone()
- }else{
- info.onUpdate && info.onUpdate(0) //初始化progress
-
- let posChange = !this.position.equals(endPosition)
- if(posChange){
- posWaitDone = true
- transitions.start(lerp.vector(this.position, endPosition, (pos, progress, delta)=>{
-
- info.onUpdate && info.onUpdate(progress, delta)
-
- }), info.duration, posDone , 0, info.Easing ? easing[info.Easing] : easing.easeInOutSine ,null, this.FlyTransition, ()=>{
- //中途取消
- if(endTarget ){
- /* endPosition = new THREE.Vector3().copy(this.position)//更改旋转的endQuaternion
- endQuaternion = math.getQuaFromPosAim(endPosition,endTarget) */
- //直接改变endQuaternion会突变,所以还是cancel吧
- this.cancelFlying('rotate')
- }
- posWaitDone = false
- info.cancelFun && info.cancelFun()
- }, info.ignoreFirstFrame);
- }
-
- if(endQuaternion || endYaw != void 0){
- rotWaitDone = true
- transitions.start( (progress, delta )=>{
- if(endYaw != void 0){
- this.yaw = startYaw * (1-progress) + endYaw * progress
- this.pitch = startPitch * (1-progress) + endPitch * progress
- }else{
- let quaternion = (new THREE.Quaternion()).copy(startQuaternion)
- lerp.quaternion(quaternion, endQuaternion)(progress) //在垂直的视角下的角度突变的厉害,这时候可能渐变yaw比较好
- //console.log(quaternion)
- //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, ()=>{
- //中途取消
- rotWaitDone = false
- info.cancelFun && info.cancelFun()
- }, info.ignoreFirstFrame);
-
- }
-
-
-
- /* transitions.start(lerp.vector(this.position, endPosition, (pos, progress)=>{
- let t = progress
-
- if(endQuaternion){
- let quaternion = (new THREE.Quaternion()).copy(startQuaternion)
- lerp.quaternion(quaternion, endQuaternion)(progress),
- this.rotation = new THREE.Euler().setFromQuaternion(quaternion)
- }
- this.restrictPos()
- //console.log('setView flying')
-
- info.onUpdate && info.onUpdate(t)//add
- }), info.duration, done, 0, info.Easing ? easing[info.Easing] : easing.easeInOutSine ,null, this.LookTransition, info.cancelFun); //easeInOutQuad
- */
- }
- }
-
-
- //平移Ortho相机
- moveOrthoCamera(viewport, info, duration, easeName){//boundSize优先于endZoom。
- let camera = info.camera || viewport.camera
-
- let startZoom = camera.zoom
- let endPosition = info.endPosition
- let boundSize = info.boundSize
- let endZoom = info.endZoom
- let margin = info.margin || {x:0,y:0}/* 200 */ //像素
- let onUpdate = info.onUpdate
-
-
-
- if(info.bound){//需要修改boundSize以适应相机的旋转,当相机不在xy水平面上朝向z时
- endPosition = endPosition || info.bound.getCenter(new THREE.Vector3())
-
- let matrixRot = new THREE.Matrix4().makeRotationFromEuler(this.rotation).invert()
- let boundingBox = info.bound.clone().applyMatrix4(matrixRot)
- boundSize = boundingBox.getSize(new THREE.Vector3())
-
- }
-
- if(boundSize && boundSize.x == 0 && boundSize.y == 0){
- boundSize.set(1,1) //避免infinity
- }
-
-
-
-
- this.setView( Object.assign(info, { position:endPosition, duration,
-
- onUpdate:(progress, delta)=>{
- if(boundSize || endZoom){
- if(boundSize){
- let aspect = boundSize.x / boundSize.y
- let w, h;
-
- if(camera.aspect > aspect){//视野更宽则用bound的纵向来决定
- h = boundSize.y
- endZoom = (viewport.resolution.y - margin.y) / h //注意,要在resolution不为0时执行
- }else{
- w = boundSize.x;
- endZoom = (viewport.resolution.x - margin.x) / w
- }
- //onUpdate时更新endzoom是因为画布大小可能更改
- }
-
- camera.zoom = endZoom * progress + startZoom * (1 - progress)
- camera.updateProjectionMatrix()
- onUpdate && onUpdate(progress, delta)
- }
- },
-
- Easing:easeName
-
- }))
-
-
- }
-
-
-
- zoomOrthoCamera(camera, endZoom, pointer, duration, onProgress){//定点缩放
-
- let startZoom = camera.zoom
-
- let pointerPos = new THREE.Vector3(pointer.x, pointer.y,0.5);
-
-
- transitions.start(( progress)=>{
- let oldPos = pointerPos.clone().unproject(camera);
-
- camera.zoom = endZoom * progress + startZoom * (1 - progress)
- camera.updateProjectionMatrix()
-
-
- let newPos = pointerPos.clone().unproject(camera);
-
- //定点缩放, 恢复一下鼠标所在位置的位置改变量
- let moveVec = new THREE.Vector3().subVectors(newPos, oldPos)
-
- camera.position.sub(moveVec)
- this.position.copy(camera.position)
-
- onProgress && onProgress()
-
- } , duration, null/* done */, 0, easing.easeInOutSine, null, "zoomInView"/* , info.cancelFun */);
-
-
-
-
- }
-
-
- tranCamera(viewport, info, duration, easeName){
- viewport.camera = info.midCamera
- //viewport.camera.matrixWorld = info.endCamera.matrixWorld
-
-
- //viewer.setCameraMode(CameraMode.ORTHOGRAPHIC)
- info.midCamera.projectionMatrix.copy(info.startCamera.projectionMatrix)
-
- let onUpdate = info.onUpdate
- info.onUpdate = (progress, delta)=>{
- lerp.matrix4(info.midCamera.projectionMatrix, info.endCamera.projectionMatrix)(progress)
-
- onUpdate && onUpdate(progress, delta)
- }
-
- let callback = info.callback
- info.callback = ()=>{
- viewport.camera = info.endCamera
- viewer.scene.measurements.forEach((e)=>{
- Potree.Utils.updateVisible(e, 'tranCamera', true)
- })
- this.applyToCamera(viewport.camera)
- viewer.dispatchEvent({type:'camera_changed', viewport:viewer.mainViewport, changeInfo:{}})//update sprite
-
- callback && callback()
- }
- //info.forbitCancel = true
-
- info.camera = info.endCamera
-
- if(info.camera.type == "OrthographicCamera"){
- this.moveOrthoCamera(viewport, info, duration, easeName)
- }else{
- this.setView( Object.assign(info, { duration}) )
- }
-
- }
-
-
-
- };
- //Object.assign(ExtendView.prototype, THREE.EventDispatcher.prototype)
- export {ExtendView}
|