123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490 |
- /**
- * @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 {Buttons} from "../defines.js";
- import {Utils} from "../utils.js";
- import {EventDispatcher} from "../EventDispatcher.js";
- let minRadius = 2
-
- export class OrbitControls extends EventDispatcher{
-
- constructor(viewer){
- super();
-
- this.viewer = viewer;
- this.renderer = viewer.renderer;
- this.scene = null;
- this.sceneControls = new THREE.Scene();
- this.rotationSpeed = 3; //旋转速度
-
-
- this.fadeFactor = 100;
- this.yawDelta = 0;
- this.pitchDelta = 0;
- this.panDelta = new THREE.Vector2(0, 0);
- this.radiusDelta = 0;
- this.doubleClockZoomEnabled = true;
- this.tweens = [];
- this.dollyStart = new THREE.Vector2
- this.dollyEnd = new THREE.Vector2
-
-
- 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)],
- };
-
-
- let drag = (e) => {
- if(!this.enabled)return
-
- let viewport = e.dragViewport;
- if(!viewport || viewport.camera.type == "OrthographicCamera" )return
- //let camera = viewport.camera
-
- if (e.drag.object !== null) {
- return;
- }
- let mode
-
- if(e.isTouch){
-
- if(e.touches.length == 1){
- mode = 'rotate'
- }else{
- mode = 'scale-pan'
- }
- }else{
- mode = e.buttons === Buttons.LEFT ? 'rotate' : 'pan'
- }
-
- if (e.drag.startHandled === undefined) {
- e.drag.startHandled = true;
- this.dispatchEvent({type: 'start'});
- }
-
- let ndrag = e.drag.pointerDelta.clone()//.add(new THREE.Vector2(1,1)).multiplyScalar(0.5)
- ndrag.y *= -1
- if (mode == 'rotate') {
-
- this.yawDelta += ndrag.x * this.rotationSpeed;
- this.pitchDelta += ndrag.y * this.rotationSpeed;
-
- } else if(mode == 'pan'){
-
- this.panDelta.x += ndrag.x;
- this.panDelta.y += ndrag.y;
-
- }else if(mode == 'scale-pan'){ //add
- this.dollyEnd.subVectors(e.touches[0].pointer, e.touches[1].pointer);
- var scale = this.dollyEnd.length() / this.dollyStart.length()
-
- this.dollyStart.copy(this.dollyEnd);
- this.radiusDelta = (1-scale) * this.scene.view.radius
-
- //------------------------
- //平移
- let pointer = new THREE.Vector2().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
-
- let delta = new THREE.Vector2().subVectors(pointer, this.lastScalePointer)
- delta.y *= -1
- this.panDelta.add(delta)
-
- this.lastScalePointer = pointer.clone()
-
-
-
- //console.log('scale ',scale, this.radiusDelta)
-
- }
-
- this.stopTweens();
-
-
- };
-
-
-
-
-
-
- let drop = e => {
- if(!this.enabled)return
- this.dispatchEvent({type: 'end'});
- };
- let scroll = (e) => {
- if(!this.enabled)return
- let resolvedRadius = this.scene.view.radius + this.radiusDelta;
- if(resolvedRadius < 0.1 && e.delta>0)return; //防止缩放太小,导致很慢
- this.radiusDelta += -e.delta * resolvedRadius * 0.1;
-
- this.stopTweens();
- };
- let dblclick = (e) => {
- if(!this.enabled)return
- if(this.doubleClockZoomEnabled){
- this.zoomToLocation(e.mouse);
- }
- };
- let previousTouch = null;
- let touchStart = e => {
- previousTouch = e;
- };
- let touchEnd = e => {
- previousTouch = e;
- };
- let touchMove = e => {
- if(!this.enabled)return
- if (e.touches.length === 2 && previousTouch.touches.length === 2){
- let prev = previousTouch;
- let curr = e;
- let prevDX = prev.touches[0].pageX - prev.touches[1].pageX;
- let prevDY = prev.touches[0].pageY - prev.touches[1].pageY;
- let prevDist = Math.sqrt(prevDX * prevDX + prevDY * prevDY);
- let currDX = curr.touches[0].pageX - curr.touches[1].pageX;
- let currDY = curr.touches[0].pageY - curr.touches[1].pageY;
- let currDist = Math.sqrt(currDX * currDX + currDY * currDY);
- let delta = currDist / prevDist;
- let resolvedRadius = this.scene.view.radius + this.radiusDelta;
- let newRadius = resolvedRadius / delta;
- this.radiusDelta = newRadius - resolvedRadius;
- this.stopTweens();
- }else if(e.touches.length === 3 && previousTouch.touches.length === 3){
- let prev = previousTouch;
- let curr = e;
- let prevMeanX = (prev.touches[0].pageX + prev.touches[1].pageX + prev.touches[2].pageX) / 3;
- let prevMeanY = (prev.touches[0].pageY + prev.touches[1].pageY + prev.touches[2].pageY) / 3;
- let currMeanX = (curr.touches[0].pageX + curr.touches[1].pageX + curr.touches[2].pageX) / 3;
- let currMeanY = (curr.touches[0].pageY + curr.touches[1].pageY + curr.touches[2].pageY) / 3;
- let delta = {
- x: (currMeanX - prevMeanX) / this.renderer.domElement.clientWidth,
- y: (currMeanY - prevMeanY) / this.renderer.domElement.clientHeight
- };
- this.panDelta.x += delta.x;
- this.panDelta.y += delta.y;
- this.stopTweens();
- }
- previousTouch = e;
- };
- this.addEventListener('touchstart', touchStart);
- this.addEventListener('touchend', touchEnd);
- this.addEventListener('touchmove', touchMove);
- this.viewer.addEventListener('global_drag', drag);
- this.viewer.addEventListener('global_drop', drop);
- this.viewer.addEventListener('global_mousewheel', scroll);
- this.viewer.addEventListener('global_dblclick', dblclick);
- this.viewer.addEventListener('global_touchmove', (e)=>{
- if(e.touches.length>1){//单指的就触发上一句
- //console.log('global_touchmove' )
- drag(e)
- }
- });
- let prepareScale = (e)=>{//触屏的scale
- this.dollyStart.subVectors(e.touches[0].pointer, e.touches[1].pointer);
- this.lastScalePointer = new THREE.Vector2().addVectors(e.touches[0].pointer, e.touches[1].pointer).multiplyScalar(0.5);//两个指头的中心点
-
- }
-
- this.viewer.addEventListener('global_touchstart', (e)=>{
- if(this.enabled && e.touches.length==2){//只监听开头两个指头
- prepareScale(e)
- }
- })
- /* this.viewer.addEventListener('global_touchend', (e)=>{
- if(!this.enabled)return
- if(e.touches.length==1){//停止scale,开始rotate
- prepareRotate(e)
- //this.pointerDragStart = null
- //console.log('只剩一个', e.pointer.toArray())
- }
- }) */
-
-
- this.viewer.addEventListener('focusOnObject',(o)=>{
- if(o.position && o.CamTarget){
- let distance = o.position.distanceTo(o.CamTarget)
- if(distance < minRadius) minRadius = distance * 0.5 //融合页面当focus一个很小的物体时,需要将minRadius也调小
- }
- })
-
- }
- setScene (scene) {
- this.scene = scene;
- }
- setEnable(enabled){
- this.enabled = enabled
- }
- stop(){
- this.yawDelta = 0;
- this.pitchDelta = 0;
- this.radiusDelta = 0;
- this.panDelta.set(0, 0);
- }
-
- /* zoomToLocation(mouse){
- if(!this.enabled)return
- let camera = this.scene.getActiveCamera();
-
- let I = Utils.getMousePointCloudIntersection(
- null, mouse, this.viewer.inputHandler.pointer,
- camera,
- this.viewer,
- this.scene.pointclouds,
- {pickClipped: true});
-
- if (I === null) {
- return;
- }
- let targetRadius = 0;
- {
- let minimumJumpDistance = 0.2;
- let domElement = this.renderer.domElement;
- let ray = Utils.mouseToRay(this.viewer.inputHandler.pointer , camera, domElement.clientWidth, domElement.clientHeight);
- 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.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);
- });
- tween.onComplete(() => {
- this.tweens = this.tweens.filter(e => e !== tween);
- });
- tween.start();
- }
- } */
-
- zoomToLocation(mouse){
- let I = viewer.inputHandler.intersect;
-
- if(!I)return
-
- let object = I.object || I.pointcloud;
- I = I.location
-
-
- if(!I || !object)return;
-
- let dis = this.scene.view.position.distanceTo(I);
-
-
- let bound = object.boundingBox.clone().applyMatrix4(object.matrixWorld)
- let size = bound.getSize(new THREE.Vector3);
- let len = size.length()
-
- let distance = THREE.Math.clamp(dis, 0.1, Math.max(len * 0.1, 3) );
-
- minRadius = distance
- viewer.focusOnObject({ position:I }, 'point', null, {distance})
-
- }
- stopTweens () {
- this.tweens.forEach(e => e.stop());
- this.tweens = [];
- }
- update (delta) {
- if(!this.enabled)return
- let view = this.scene.view;
- { // 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 px = 0 , py = 0, pz = 0
- if(moveForward){
- py = 1
- }else if(moveBackward){
- py = -1
- }
-
- if(moveLeft){
- px = -1
- }else if(moveRight){
- px = 1
- }
- if(moveUp){
- pz = 1
- }else if(moveDown){
- pz = -1
- }
-
- (px!=0 || py!=0 || pz!=0) && view.translate(px, py, pz, true);
-
- }
-
-
- { // apply rotation
- let progression = Math.min(1, this.fadeFactor * delta);
- let yaw = view.yaw;
- let pitch = view.pitch;
- let pivot = view.getPivot();
- yaw -= progression * this.yawDelta;
- pitch -= progression * this.pitchDelta;
- view.yaw = yaw;
- view.pitch = pitch;
- let V = this.scene.view.direction.multiplyScalar(-view.radius);
- let position = new THREE.Vector3().addVectors(pivot, V);
- view.position.copy(position);
- }
- { // 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。
-
- let px = -this.panDelta.x * panDistance;
- let py = this.panDelta.y * panDistance;
- view.pan(px, py);
- }
- { // apply zoom
- let progression = 1//Math.min(1, this.fadeFactor * delta);
-
-
-
- // let radius = view.radius + progression * this.radiusDelta * view.radius * 0.1;
- let radius = view.radius + progression * this.radiusDelta;
-
- let V = view.direction.multiplyScalar(-radius);
- let position = new THREE.Vector3().addVectors(view.getPivot(), V);
-
- if(this.constantlyForward) {// 到达中心点后还能继续向前移动,也就是能推进中心点
- if(radius < minRadius){
- radius = minRadius
- }
- }
- view.radius = radius;
- view.position.copy(position);
- }
- {
- let speed = view.radius;
- this.viewer.setMoveSpeed(speed);
- }
- { // decelerate over time
- /* let progression = Math.min(1, this.fadeFactor * delta);
- let attenuation = Math.max(0, 1 - this.fadeFactor * delta);
- this.yawDelta *= attenuation;
- this.pitchDelta *= attenuation;
- this.panDelta.multiplyScalar(attenuation);
- // this.radiusDelta *= attenuation;
- this.radiusDelta -= progression * this.radiusDelta; */
-
- //取消衰减,直接stop
- this.stop()
- }
- }
- };
|