123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888 |
- /**
- * @author mschuetz / http://mschuetz.at
- *
- * adapted from THREE.OrbitControls by
- *
- * @author qiao / https://github.com/qiao
- * @author mrdoob / http://mrdoob.com
- * @author alteredq / http://alteredqualia.com/
- * @author WestLangley / http://github.com/WestLangley
- * @author erich666 / http://erichaines.com
- *
- *
- *
- */
- import * as THREE from "../../libs/three.js/build/three.module.js";
- 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 {
- constructor (viewer, viewport) {
- super();
-
- this.viewer = viewer;
- this.renderer = viewer.renderer;
- this.scene = viewer.scene;
-
- this.rotationSpeed = 200;
- this.moveSpeed = 10;
-
-
- this.setCurrentViewport({hoverViewport:viewport, force:true}) //this.currentViewport = viewport
-
-
-
- this.keys = {
- FORWARD: ['W'.charCodeAt(0), 38],
- BACKWARD: ['S'.charCodeAt(0), 40],
- LEFT: ['A'.charCodeAt(0), 37],
- RIGHT: ['D'.charCodeAt(0), 39],
- UP: ['Q'.charCodeAt(0)],
- DOWN: ['E'.charCodeAt(0)],
-
- //SHIFT : [16],
- ALT : [18],
- Rotate_LEFT : ['L'.charCodeAt(0)],
- Rotate_RIGHT : ['J'.charCodeAt(0)],
- Rotate_UP : ['K'.charCodeAt(0)],
- Rotate_DOWN : ['I'.charCodeAt(0)],
- };
- this.fadeFactor = 20;
- this.yawDelta = 0;
- this.pitchDelta = 0;
- this.translationDelta = new THREE.Vector3(0, 0, 0);
- this.translationWorldDelta = new THREE.Vector3(0, 0, 0);
- this.tweens = [];
- this.dollyStart = new THREE.Vector2
- this.dollyEnd = new THREE.Vector2
- //this.enableChangePos = true
-
- this.viewer.addEventListener('camera_changed',(e)=>{
- if(this.viewer.name == 'mapViewer' || e.changeInfo && e.changeInfo.positionChanged && !viewer.mainViewport.view.isFlying() ){
- this.setFPCMoveSpeed(e.viewport)
- }
- })
-
- let drag = (e) => {
- if(!this.enabled)return
- let viewport = e.dragViewport;
- if(!viewport)return
- let camera = viewport.camera
- let mode
-
-
- if(e.isTouch){
- if(e.touches.length == 1){
- mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan'
- }else if(e.touches.length == 2){
- mode = Potree.settings.displayMode == 'showPanos' ? 'scale' : 'pan-scale'
- }else{
- mode = (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'pan' : 'scale'
- }
- }else{
- //mode = e.buttons === Buttons.LEFT && (!e.dragViewport || e.dragViewport.name == 'MainView') ? 'rotate' : 'pan'
- mode = e.buttons === Buttons.LEFT && camera.type != 'OrthographicCamera' ? 'rotate' : 'pan'
- }
-
-
-
- //console.log('mode ', mode )
- let moveSpeed = this.currentViewport.getMoveSpeed();
- if (e.drag.startHandled === undefined) {///???????
- e.drag.startHandled = true;
- this.dispatchEvent({type: 'start'});
- }
-
-
- if (mode.includes('rotate')) {//旋转
-
- //来自panoramaControl updateRotation
- if(!this.pointerDragStart){
- return this.pointerDragStart = e.pointer.clone()
- }
-
-
- let view = this.scene.view;
-
-
- if(this.rotateStartInfo.rotAroundPoint){//定点旋转: 以当前intersect的点为target旋转,不改点在屏幕中的位置
-
- let distance = camera.position.distanceTo(this.rotateStartInfo.rotCenter/* this.intersectStart.location */) //不按下ctrl的话
-
- if(this.rotateStartInfo.rotCenter2d.z>1)distance *= -1 //在背面
-
- //按照orbitControl的方式旋转:
- let rotationSpeed = 2;
- this.yawDelta -= e.drag.pointerDelta.x * rotationSpeed;
- this.pitchDelta += e.drag.pointerDelta.y * rotationSpeed;
- /* //旋转方向和偏移量尽量和在漫游点处旋转方式的一样
- this.yawDelta += e.drag.pointerDelta.x / 500 * viewport.resolution.x
- this.pitchDelta -= e.drag.pointerDelta.y / 500 * viewport.resolution.y */
-
- //先更新一下相机:
- this.update()
- view.applyToCamera(camera)
-
- //然后得到新的相机角度下,原先点在屏幕中的位置所对应的3d点现在的坐标。只需要平移一下新旧坐标差值即可。//感觉貌似也可以用project和unproject后的差值的方式,还不用判断z背面
- let newPointerDir = viewer.inputHandler.getMouseDirection(this.rotateStartInfo.rotCenter2d).direction.clone().multiplyScalar(distance)
- let pivot = new THREE.Vector3().addVectors(camera.position, newPointerDir) //新的3d点
-
- let moveVec = new THREE.Vector3().subVectors(pivot, this.rotateStartInfo.rotCenter)
-
- this.translationWorldDelta.copy(moveVec.negate())
- //立即更新下,防止因update和此drag频率不同而打滑。
- this.update()
- view.applyToCamera(camera)
-
-
- }else{
-
-
- let _matrixWorld = camera.matrixWorld
- camera.matrixWorld = new THREE.Matrix4;//unproject 前先把相机置于原点
-
- var e1 = new THREE.Vector3(this.pointerDragStart.x,this.pointerDragStart.y,-1).unproject(camera)
- , t = new THREE.Vector3(e.pointer.x,e.pointer.y,-1).unproject(camera)
- , i = Math.sqrt(e1.x * e1.x + e1.z * e1.z)
- , n = Math.sqrt(t.x * t.x + t.z * t.z)
- , o = Math.atan2(e1.y, i)
- , a = Math.atan2(t.y, n);
-
- this.pitchDelta += o - a //上下旋转
- e1.y = 0,
- t.y = 0;
-
- var s = Math.acos(e1.dot(t) / e1.length() / t.length());
-
- if(!isNaN(s)){
- var yawDelta = s //左右旋转
- this.pointerDragStart.x > e.pointer.x && (yawDelta *= -1)
- this.yawDelta += yawDelta
- }
-
-
- //console.log('rotate:', this.pitchDelta, e.pointer.toArray(), this.pointerDragStart.toArray())
-
-
- this.pointerDragStart.copy(e.pointer)
-
- camera.matrixWorld = _matrixWorld ;
-
-
-
- }
- }
-
- if (mode.includes('pan')) {//平移
- if(!this.canMovePos(viewport)){
- return
- }
-
- if(camera.type == "OrthographicCamera"){
-
- //console.log(e.drag.pointerDelta, e.pointer, e.drag.end)
- let moveVec = Utils.getOrthoCameraMoveVec(e.drag.pointerDelta, camera )//最近一次移动向量
-
- let pointclouds;
- let Alignment = window.viewer.modules.Alignment
- let MergeEditor = window.viewer.modules.MergeEditor
- let handleState = Alignment.handleState
- //右键平移视图、左键操作点云
- let a = e.buttons === Buttons.LEFT && viewport.alignment && handleState && viewport.alignment[handleState]
- if(Potree.settings.editType == 'pano'){
- let PanoEditor = window.viewer.modules.PanoEditor
-
- if(a && PanoEditor.selectedPano){
- if(/* !PanoEditor.selectedGroup || */!PanoEditor.checkIfAllLinked({group:PanoEditor.selectedGroup}) ){
- if(handleState == 'translate' && ( e.drag.intersectStart.pointclouds && Common.getMixedSet(PanoEditor.selectedClouds, e.drag.intersectStart.pointclouds).length || PanoEditor.selectedPano.hovered)//平移时 拖拽到点云上 或 circle。(其中点云只需要intersect的点云中包含选择的点云中之一即可)
- || handleState == 'rotate' ) //旋转模式不需要intersect
- {
- pointclouds = PanoEditor.selectedClouds
- }
- }else{
- PanoEditor.dispatchEvent('needToDisConnect')
- console.warn('选中的漫游点连通了整个数据集,不允许移动')
- }
- }
-
- if(!pointclouds && e.buttons === Buttons.LEFT && viewport.rotateSide){//侧视图 (有时候会卡顿,是mousemove执行延迟了,一般发生在突然加载很多点云时)
- //console.log('rotateSide', -e.drag.pointerDelta.x )
- return PanoEditor.rotateSideCamera(-e.drag.pointerDelta.x)
- }
- }else if(Potree.settings.editType == 'merge'){
- if(e.buttons === Buttons.LEFT && viewport.rotateSide){
- 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]
- //}
-
- if(a && e.drag.intersectStart.pointcloud){
- pointclouds = [e.drag.intersectStart.pointcloud]
- if(e.drag.intersectStart.pointcloud.dataset_id == Potree.settings.originDatasetId){
- let p = e.drag.intersectStart.pointclouds.find(p=>p.dataset_id != Potree.settings.originDatasetId)
- if(p) pointclouds = [p]
- }
- }
-
-
-
- }
-
- if(pointclouds){
- if(handleState == 'translate' && viewport.alignment.translateVec){//只能沿某个方向移动
- moveVec.projectOnVector(viewport.alignment.translateVec)
- }
-
- this.dispatchEvent({
- type : "transformPointcloud",
- intersect: e.intersect.orthoIntersect,
- intersectStart: e.drag.intersectStart.orthoIntersect,
- moveVec,
- pointclouds,
- camera
- })
- }else{
- this.translationWorldDelta.add(moveVec.negate())
- }
-
- }else{ //perspectiveCamera:
- if(e.drag.intersectStart){//如果拖拽着点云
- let ifInit = e.drag.z == void 0
- let pointerStartPos2d = e.drag.intersectStart.location.clone().project(camera);//识别到的点云点的位置
- e.drag.z = pointerStartPos2d.z //记录z,保持拖拽物体到屏幕距离不变,所以z深度不变(如果拖拽过程中没有缩放,这个z其实不变)
-
- if(ifInit){//拖拽开始
-
-
- e.drag.projectionMatrixInverse = camera.projectionMatrixInverse.clone()
- //防止吸附到最近点上(因为鼠标所在位置并非识别到的点云点的位置,需要得到鼠标所在位置的3d坐标。)
- let pointerStartPos2dReal = new THREE.Vector3(this.pointerDragStart.x,this.pointerDragStart.y, e.drag.z);
- e.drag.translateStartPos = pointerStartPos2dReal.clone().unproject(camera);
- //console.log('开始拖拽', e.pointer.clone())
- }
- //拖拽的过程中将projectionMatrixInverse替换成开始拖拽时的,因为near、far一直在变,会导致unproject计算出的3d坐标改变很大而闪烁。
- var _projectionMatrixInverse = camera.projectionMatrixInverse;
- camera.projectionMatrixInverse = e.drag.projectionMatrixInverse;
-
-
- let newPos2d = new THREE.Vector3(e.pointer.x,e.pointer.y, e.drag.z );
- let newPos3d = newPos2d.clone().unproject(camera);
- let moveVec = newPos3d.clone().sub( e.drag.translateStartPos /* e.drag.intersectStart.location */ );//移动相机,保持鼠标下的位置永远不变,所以用鼠标下的新位置减去鼠标下的原始位置
-
-
- camera.projectionMatrixInverse = _projectionMatrixInverse
- this.translationWorldDelta.copy(moveVec.negate()) //这里没法用add,原因未知,打开console时会跳动
- //console.log('pan 1', this.translationWorldDelta.clone())
-
- //四指松开剩三指时会偏移一下,暂不知道哪里的问题,或许跟开头防止点云吸附有关?
-
- }else{ //如果鼠标没有找到和点云的交点,就假设移动整个模型(也可以去扩大范围寻找最近点云)
-
- /* let center = viewer.scene.pointclouds[0].position;
- let radius = camera.position.distanceTo(center);
- let ratio = radius * Math.tan(THREE.Math.degToRad(camera.fov)/2) / 1000 */
-
-
- /* let speed = this.currentViewport.getMoveSpeed()
- if(FirstPersonControls.boundPlane){
- speed = FirstPersonControls.boundPlane.distanceToPoint(this.currentViewport.position)
- speed = Math.max(1 , speed)
- } */
- let lastIntersect = this.target || viewport.lastIntersect && (viewport.lastIntersect.location || viewport.lastIntersect)//该viewport的最近一次鼠标和点云的交点
- if(!lastIntersect || !(lastIntersect instanceof THREE.Vector3))lastIntersect = viewer.bound.center
- let speed = camera.position.distanceTo(lastIntersect)
- let fov = cameraLight.getHFOVForCamera(camera, true)
- let ratio = speed * Math.tan(fov/2)
- this.translationDelta.x -= e.drag.pointerDelta.x * ratio
- this.translationDelta.z -= e.drag.pointerDelta.y * ratio
- //console.log('pan2', e.drag.pointerDelta)
- }
- }
- this.useAttenuation = false
-
-
-
- }
-
-
- if(mode.includes('scale')){//触屏缩放
-
-
- this.dollyEnd.subVectors(e.touches[0].pointer, e.touches[1].pointer);
- //if(!this.dollyStart)return
- var scale = this.dollyEnd.length() / this.dollyStart.length()
-
- let pointer = new THREE.Vector2().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
-
- dolly({
- pointer,
- scale, camera, drag:e.drag
- })
- this.dollyStart.copy(this.dollyEnd);
-
- }
- //最好按ctrl可以变为dollhouse的那种旋转
- };
- let drop = e => {
- if(!this.enabled)return
- this.dispatchEvent({type: 'end'});
-
- };
- let dolly = (e={})=>{
-
- if(Potree.settings.displayMode == 'showPanos' && this.currentViewport == viewer.mainViewport/* this.currentViewport.unableChangePos */){//全景时
- this.dispatchEvent({type:'dollyStopCauseUnable',delta:e.delta, scale:e.scale})
- return
- }
-
- let camera = e.camera
-
-
- if(camera.type == "OrthographicCamera"){
- let ratio
- if(e.delta != void 0){//滚轮缩放
- if(e.delta == 0){//mac
- return
- }else if (e.delta < 0) {
- ratio = 0.9
- } else if (e.delta > 0) {
- ratio = 1.12 //增加的需要比减少的多一些,否则缩放相同次数下,r0 * ([1+s)(1-s)]^n = r0 * (1-s^2)^n < r0
- }
- }else{
- ratio = e.scale //触屏缩放
- }
-
- let zoom = camera.zoom * ratio
- let limit = camera.zoomLimit
- if(limit) zoom = THREE.Math.clamp(zoom, limit.min,limit.max )
-
-
- let pointerPos = new THREE.Vector3(e.pointer.x, e.pointer.y,0.5);
- let oldPos = pointerPos.clone().unproject(camera);
-
- if(camera.zoom != zoom){
- camera.zoom = zoom
- camera.updateProjectionMatrix()
- }
- let newPos = pointerPos.clone().unproject(camera);
-
- //定点缩放, 恢复一下鼠标所在位置的位置改变量
- let moveVec = new THREE.Vector3().subVectors(newPos,oldPos)
- this.translationWorldDelta.add(moveVec.negate())
- this.useAttenuation = false
- }else{
- let speed = this.currentViewport.getMoveSpeed() * 15, direction
-
-
- if(e.delta != void 0){//滚轮缩放
- if(e.delta == 0)return //mac
-
- /*if(this.target && !e.intersect){//如果没有intersect点云且有target的话,就朝target的方向. 但无限靠近时有问题,且到背面时前进却是后退
- direction = new THREE.Vector3().subVectors(this.target, camera.position).normalize()
- }else{ */
- direction = this.viewer.inputHandler.getMouseDirection().direction //定点缩放
-
- if(e.intersect && e.intersect.location){//和intersect的墙越接近,速度越慢,便于focus细节
- let dis = camera.position.distanceTo(e.intersect.location);
-
- speed = THREE.Math.clamp(dis * 0.1, 0.3, speed)
- }
- if (e.delta < 0) {
- speed *= -1
- }
- this.useAttenuation = true
- }else{//触屏缩放
- direction = this.viewer.inputHandler.getMouseDirection(e.pointer).direction //定点缩放
-
- if(e.drag.intersectStart){//和intersect的墙越接近,速度越慢,便于focus细节
- let dis = camera.position.distanceTo(e.drag.intersectStart.location);
-
-
- let r = 1-1/e.scale
- let closeMin = 0.1, standardMin = 0.001, disBound1 = 2, disBound2 = 5
-
- if(math.closeTo(e.scale,1,0.03)){//如果偏差小于0.01,就不限制最小值,因为平移容易正负抖动,近距离有最小值的话抖动明显
- closeMin = 0 //所以若缩放不明显(双指滑动慢),就不设置最低值。(这时候穿越障碍物会比较困难。)
- }
- //console.log('closeMin',closeMin)
- let min = math.linearClamp(dis, disBound1, disBound2, closeMin, standardMin) //触屏和滚轮不一样,触发较为连续,所以最小值设低一点。若要保持双指相对点云位置不变,理想最小值是0,但那样就无法穿越点云(最小值太小的话穿越密集点云如树丛很困难;太大会打滑)所以当离点云近时增大最小值
- speed = Math.sign(r) * THREE.Math.clamp(dis * Math.abs(r), min, speed)
-
- //console.log(speed, dis, e.scale)
-
- }else{
-
- this.useAttenuation = true
- let accelerate = 80;
- if(math.closeTo(e.scale,1,0.02)){//缩放小的时候很可能是双指平移时,容易抖动,所以降低移动速度
- accelerate *= Math.min(40*Math.abs(e.scale-1), 0.8)
- }
- // console.log('accelerate',accelerate)
- const constantDis = this.currentViewport.getMoveSpeed() * accelerate //constantDis = 10;//常量系数,当放大一倍时前进的距离。可以调整
- speed = (e.scale-1)*constantDis
- }
-
- }
-
- var vec = direction.multiplyScalar(speed )
- //this.translationWorldDelta.copy(vec)
- this.translationWorldDelta.add(vec)
- //console.log(direction.toArray(), speed, e.scale)
- }
- return true
- }
- let scroll = (e) => {
- if(!this.enabled || !e.hoverViewport)return
- this.setCurrentViewport(e)
-
-
- e.camera = e.hoverViewport.camera
- dolly(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);
- };
- this.viewer.addEventListener('global_drag', drag);
- /* this.viewer.addEventListener('global_touchmove', (e)=>{
- if(!this.enabled)return
- if(e.touches.length>1){//单指的就触发上一句
- //console.log('global_touchmove' )
- drag(e)
- }
- }); */
- this.viewer.addEventListener('global_drop', drop);
- this.viewer.addEventListener('global_mousewheel', scroll);
- this.viewer.addEventListener('global_dblclick', dblclick);
-
-
-
- let prepareScale = (e)=>{//触屏的scale
- this.dollyStart.subVectors(e.touches[0].pointer, e.touches[1].pointer);
- e.drag.camDisToPointStart = null
- }
- let prepareRotate = (e)=>{
- this.pointerDragStart = e.pointer.clone()
- if(e.viewer.name != 'mainViewer' )return
- let intersect = e.intersect || e.dragViewport.lastIntersect
- //在数据集外部时绕中心点旋转,在数据集内部时绕intersect点旋转(其他数据集的点也可以) 或者 原地旋转镜头
- let rotAroundPoint = Potree.settings.rotAroundPoint && e.dragViewport.camera.type != 'OrthographicCamera' && (viewer.atDatasets.length == 0 || intersect) && this.canMovePos(viewport) && !viewer.images360.isAtPano() && !this.viewer.inputHandler.pressedKeys[32]
- let rotCenter2d, rotCenter
- if(rotAroundPoint){
- let pivotType = this.target ? 'target' : viewer.atDatasets.length > 0 ? 'intersect' : viewer.inputHandler.selection.length ? 'selection' : this.target2 ? 'target2' : 'boundCenter'
- rotCenter = pivotType == 'target'? this.target :pivotType == 'intersect' ? intersect.location : pivotType == 'selection' ? viewer.inputHandler.selection[0].position : pivotType == 'target2' ? this.target2 :viewer.bound.center
- if(rotCenter){
- rotCenter2d = rotCenter.clone().project(e.dragViewport.camera) //点在屏幕中的位置
- }else{
- rotAroundPoint = false
- }
- }
- this.rotateStartInfo = {
- rotAroundPoint, //定点旋转
- rotCenter,
- rotCenter2d
- }
- //缺点:多数据集绕中心点转很难操作,感觉可以也改为绕lastIntersect
-
- //console.log('prepareRotate' )
- }
- let preparePan = (e)=>{//触屏的pan点云 还是会偏移
- this.pointerDragStart = e.pointer.clone()
-
- e.drag.z = void 0 //清空
- drag(e) //触屏点击时更新的pointer直接用一次drag
- //console.log('preparePan ' )
- }
-
- this.viewer.addEventListener('global_mousedown'/* 'startDragging' */, (e)=>{
- if(!this.enabled)return
- this.setCurrentViewport(e)
- prepareRotate(e)
- })
-
-
- //注意,每次增减指头都会修改pointer,需要更新下状态
- this.viewer.addEventListener('global_touchstart', (e)=>{
- if(!this.enabled)return
- if(e.touches.length==2){//只监听开头两个指头
- prepareScale(e)
- preparePan(e)
- }else if(e.touches.length>=3){
- preparePan(e)
- }
- })
- this.viewer.addEventListener('global_touchend', (e)=>{//e.touches是剩余的指头
- if(!this.enabled)return
- if(e.touches.length==2){//停止平移,开始scale
- prepareScale(e)
- preparePan(e)
- }else if(e.touches.length==1){//停止scale,开始rotate
- prepareRotate(e)
- }else if(e.touches.length>=3){//重新准备下平移(因为抬起的指头可能包含平移使用的数据),否则抬起时漂移
- preparePan(e)
- }
- })
-
-
-
-
- /* this.viewer.addEventListener('enableChangePos', (e)=>{
- if(!this.enabled)return
- this.enableChangePos = e.canLeavePano
- }) */
-
- }
- canMovePos(viewport){
- if(viewport == viewer.mainViewport && (Potree.settings.displayMode == 'showPanos'
- || viewer.images360.bumping || viewer.images360.latestToPano))return false
- else return true
- }
- setEnable(enabled){
- this.enabled = enabled;
-
- }
- setTarget(target, index){//绕该点旋转,类似orbitControl
- if(index == 2)this.target2 = target
- else this.target = target
- }
- setFPCMoveSpeed(viewport){
- if(viewport.camera.type == 'OrthographicCamera'){
- let s = 1 / viewport.camera.zoom
- viewport.setMoveSpeed(s)
-
- }else{
-
- //根据和漫游点的最短距离算moveSpeed。缺点:对于导入的无漫游点的数据集没有意义。
- if(viewport == viewer.mainViewport && viewer.images360){
- let position = viewer.mainViewport.view.position
- let speed
- let pano = viewer.images360.findNearestPano()
- if(!pano){
- if(!viewer.bound)return
- let boundFloor = viewer.bound.boundingBox.clone();
- boundFloor.max.z = boundFloor.min.z
- speed = boundFloor.distanceToPoint(viewer.mainViewport.view.position)
- speed = Math.sqrt(speed) / 50;
-
- }else{
- let dis = pano.position.distanceTo(position)
- let minSpeed = 0.05, minDis = 3, multiplier = 0.005;
- speed = dis <= minDis ? minSpeed : minSpeed + (dis-minDis) * multiplier
- //console.log('dis', dis, 'speed', speed, pano.id )
- }
- viewer.setMoveSpeed(speed)
-
- }
- //调试场景t-FhDWmV5xur 两个数据集,大的数据集没有漫游点。
- }
-
- }
- setCurrentViewport(o={}){//add
- if(!this.enabled && !o.force )return
- if(o.hoverViewport && this.currentViewport != o.hoverViewport ){
- this.currentViewport = o.hoverViewport
- //this.viewer.setMoveSpeed(this.currentViewport.radius/100);
- this.setFPCMoveSpeed(this.currentViewport)
- }
-
- if(this.currentViewport.camera.type == 'OrthographicCamera'){
- this.lockElevationOri = true
- this.lockRotation = true
- }else{
- this.lockElevationOri = false
- this.lockRotation = false
- }
- }
-
- setScene (scene) {
- this.scene = scene;
-
- }
- stop(){
- this.yawDelta = 0;
- this.pitchDelta = 0;
- this.translationDelta.set(0, 0, 0);
- }
-
-
-
- zoomToLocation(mouse){
- if(!this.enabled)return
- let camera = this.scene.getActiveCamera();
-
- /* let I = Utils.getMousePointCloudIntersection(
- mouse,
- camera,
- this.viewer,
- this.scene.pointclouds); */
- var I = this.viewer.inputHandler.intersect
- if (!I) {
- return;
- }
- let targetRadius = 0;
- {
- let minimumJumpDistance = 0.2;
- let domElement = this.renderer.domElement;
-
- let ray = Utils.mouseToRay(this.viewer.inputHandler.pointer, camera);
- let {origin, direction} = this.viewer.inputHandler.getMouseDirection()
- let raycaster = new THREE.Raycaster();
- raycaster.ray.set(origin, direction);
-
- let nodes = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, ray);
-
- let nodes2 = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, raycaster.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.max(minimumJumpDistance, targetRadius);
- }
- let d = this.scene.view.direction.multiplyScalar(-1);
- let cameraTargetPosition = new THREE.Vector3().addVectors(I.location, d.multiplyScalar(targetRadius));
- // TODO Unused: let controlsTargetPosition = I.location;
- let animationDuration = 600;
- let easing = TWEEN.Easing.Quartic.Out;
- { // animate
- let value = {x: 0};
- let tween = new TWEEN.Tween(value).to({x: 1}, animationDuration);
- tween.easing(easing);
- this.tweens.push(tween);
- let startPos = this.scene.view.position.clone();
- let targetPos = cameraTargetPosition.clone();
- let startRadius = this.scene.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.scene.view.radius = (1 - t) * startRadius + t * targetRadius;
- this.viewer.setMoveSpeed(this.scene.view.radius / 2.5);
- });
- tween.onComplete(() => {
- this.tweens = this.tweens.filter(e => e !== tween);
- });
- tween.start();
- }
- }
- update (delta=1) {
- if(!this.enabled)return
-
- //console.log('update')
- let view = this.currentViewport.view
- { // cancel move animations on user input
- let changes = [ this.yawDelta,
- this.pitchDelta,
- this.translationDelta.length(),
- this.translationWorldDelta.length() ];
- let changeHappens = changes.some(e => Math.abs(e) > 0.001);
- if (changeHappens && this.tweens.length > 0) {
- this.tweens.forEach(e => e.stop());
- this.tweens = [];
- }
- }
- { // accelerate while input is given
- let ih = this.viewer.inputHandler;
- let moveForward = this.keys.FORWARD.some(e => ih.pressedKeys[e]);
- let moveBackward = this.keys.BACKWARD.some(e => ih.pressedKeys[e]);
- let moveLeft = this.keys.LEFT.some(e => ih.pressedKeys[e]);
- let moveRight = this.keys.RIGHT.some(e => ih.pressedKeys[e]);
- let moveUp = this.keys.UP.some(e => ih.pressedKeys[e]);
- let moveDown = this.keys.DOWN.some(e => ih.pressedKeys[e]);
-
- let rotateLeft = this.keys.Rotate_LEFT.some(e => ih.pressedKeys[e]);
- let rotateRight = this.keys.Rotate_RIGHT.some(e => ih.pressedKeys[e]);
- let rotateUp = this.keys.Rotate_UP.some(e => ih.pressedKeys[e]);
- let rotateDown = this.keys.Rotate_DOWN.some(e => ih.pressedKeys[e]);
-
- this.lockElevation = this.lockElevationOri || this.keys.ALT.some(e => ih.pressedKeys[e]);
-
-
-
- if(!this.lockRotation){
- if(rotateLeft){
- this.yawDelta -= 0.01
- }else if(rotateRight){
- this.yawDelta += 0.01
- }
- if(rotateUp){
- this.pitchDelta -= 0.01
- }else if(rotateDown){
- this.pitchDelta += 0.01
- }
- }
-
- if(this.canMovePos(this.currentViewport) && !this.lockKey){
- if(this.lockElevation){
- let dir = view.direction;
- dir.z = 0;
- dir.normalize();
- if (moveForward && moveBackward) {
- this.translationWorldDelta.set(0, 0, 0);
- } else if (moveForward) {
- this.translationWorldDelta.copy(dir.multiplyScalar(this.currentViewport.getMoveSpeed()));
- } else if (moveBackward) {
- this.translationWorldDelta.copy(dir.multiplyScalar(-this.currentViewport.getMoveSpeed()));
- }
- }else{
- if (moveForward && moveBackward) {
- this.translationDelta.y = 0;
- } else if (moveForward) {
- this.translationDelta.y = this.currentViewport.getMoveSpeed();
- } else if (moveBackward) {
- this.translationDelta.y = -this.currentViewport.getMoveSpeed();
- }
- }
- if (moveLeft && moveRight) {
- this.translationDelta.x = 0;
- } else if (moveLeft) {
- this.translationDelta.x = -this.currentViewport.getMoveSpeed();
- } else if (moveRight) {
- this.translationDelta.x = this.currentViewport.getMoveSpeed();
- }
- if (moveUp && moveDown) {
- this.translationWorldDelta.z = 0;
- } else if (moveUp) {
- this.translationWorldDelta.z = this.currentViewport.getMoveSpeed();
- } else if (moveDown) {
- this.translationWorldDelta.z = -this.currentViewport.getMoveSpeed();
- }
-
-
- if(moveUp || moveDown || moveForward || moveBackward){
- this.useAttenuation = false
- }
-
- }
- }
- { // apply rotation
- let yaw = view.yaw;
- let pitch = view.pitch;
-
-
- yaw += this.yawDelta /* * delta; */
- pitch += this.pitchDelta/* * delta; */
- view.yaw = yaw;
- view.pitch = pitch;
- if(this.yawDelta || this.pitchDelta){
- view.cancelFlying('rotate')
- }
-
- this.yawDelta = 0
- this.pitchDelta = 0
- }
- /* if(this.translationWorldDelta.length()>0) {
- // console.log('translationDelta')
- } */
- { // apply translation
- view.translate(
- this.translationDelta.x, /* * delta, */
- this.translationDelta.y, /* * delta, */
- this.translationDelta.z, /* * delta */
- );
- this.translationDelta.set(0,0,0)
- //if(this.translationWorldDelta.length())console.log(translationWorldDelta)
-
- view.translateWorld(
- this.translationWorldDelta.x /* * delta */,
- this.translationWorldDelta.y /* * delta */,
- this.translationWorldDelta.z /* * delta */
- );
-
-
-
- //this.translationWorldDelta.set(0,0,0)
- }
- { // set view target according to speed
- //view.radius = 1 * this.currentViewport.getMoveSpeed();
-
- /* if(viewer.bound) view.radius = view.position.distanceTo(viewer.bound.center)
- let speed = view.radius/100;
- this.viewer.setMoveSpeed(speed); */
- //this.setMoveSpeed()
-
-
- }
-
- if(this.useAttenuation){ //只有滚轮缩放时开启
- let attenuation = Math.max(0, 1 - this.fadeFactor * delta);
-
- /*this.yawDelta *= attenuation;
- this.pitchDelta *= attenuation;
- this.translationDelta.multiplyScalar(attenuation);*/
- this.translationWorldDelta.multiplyScalar(attenuation);
- }else{
-
- this.translationWorldDelta.set(0,0,0)
-
- }
- }
- };
|