UNPKG

potree

Version:

WebGL point cloud viewer - WORK IN PROGRESS

292 lines (229 loc) 8.15 kB
Potree.EarthControls = class EarthControls extends THREE.EventDispatcher { constructor (viewer) { super(viewer); this.viewer = viewer; this.renderer = viewer.renderer; this.scene = null; this.sceneControls = new THREE.Scene(); this.rotationSpeed = 10; this.fadeFactor = 20; this.wheelDelta = 0; this.zoomDelta = new THREE.Vector3(); this.camStart = null; this.tweens = []; { let sg = new THREE.SphereGeometry(1, 16, 16); let sm = new THREE.MeshNormalMaterial(); this.pivotIndicator = new THREE.Mesh(sg, sm); this.pivotIndicator.visible = false; this.sceneControls.add(this.pivotIndicator); } let drag = (e) => { if (e.drag.object !== null) { return; } if (!this.pivot) { return; } if (e.drag.startHandled === undefined) { e.drag.startHandled = true; this.dispatchEvent({type: 'start'}); } let camStart = this.camStart; let view = this.viewer.scene.view; // let camera = this.viewer.scene.camera; let mouse = e.drag.end; let domElement = this.viewer.renderer.domElement; if (e.drag.mouse === Potree.MOUSE.LEFT) { let nmouse = { x: (mouse.x / domElement.clientWidth) * 2 - 1, y: -(mouse.y / domElement.clientHeight) * 2 + 1 }; let vector = new THREE.Vector3(nmouse.x, nmouse.y, 0.5); vector.unproject(camStart); let dir = vector.sub(camStart.position).normalize(); let ray = new THREE.Ray(camStart.position, dir); let plane = new THREE.Plane().setFromNormalAndCoplanarPoint( new THREE.Vector3(0, 0, 1), this.pivot); let distanceToPlane = ray.distanceToPlane(plane); if (distanceToPlane > 0) { let I = new THREE.Vector3().addVectors( camStart.position, dir.clone().multiplyScalar(distanceToPlane)); let movedBy = new THREE.Vector3().subVectors( I, this.pivot); let newCamPos = camStart.position.clone().sub(movedBy); view.position.copy(newCamPos); { let distance = newCamPos.distanceTo(this.pivot); view.radius = distance; let speed = view.radius / 2.5; this.viewer.setMoveSpeed(speed); } } } else if (e.drag.mouse === Potree.MOUSE.RIGHT) { let ndrag = { x: e.drag.lastDrag.x / this.renderer.domElement.clientWidth, y: e.drag.lastDrag.y / this.renderer.domElement.clientHeight }; let yawDelta = -ndrag.x * this.rotationSpeed * 0.5; let pitchDelta = -ndrag.y * this.rotationSpeed * 0.2; let originalPitch = view.pitch; let tmpView = view.clone(); tmpView.pitch = tmpView.pitch + pitchDelta; pitchDelta = tmpView.pitch - originalPitch; let pivotToCam = new THREE.Vector3().subVectors(view.position, this.pivot); let pivotToCamTarget = new THREE.Vector3().subVectors(view.getPivot(), this.pivot); let side = view.getSide(); pivotToCam.applyAxisAngle(side, pitchDelta); pivotToCamTarget.applyAxisAngle(side, pitchDelta); pivotToCam.applyAxisAngle(new THREE.Vector3(0, 0, 1), yawDelta); pivotToCamTarget.applyAxisAngle(new THREE.Vector3(0, 0, 1), yawDelta); let newCam = new THREE.Vector3().addVectors(this.pivot, pivotToCam); // TODO: Unused: let newCamTarget = new THREE.Vector3().addVectors(this.pivot, pivotToCamTarget); view.position.copy(newCam); view.yaw += yawDelta; view.pitch += pitchDelta; } }; let onMouseDown = e => { let I = Potree.utils.getMousePointCloudIntersection( e.mouse, this.scene.camera, this.renderer, this.scene.pointclouds); if (I) { this.pivot = I.location; this.camStart = this.scene.camera.clone(); this.pivotIndicator.visible = true; this.pivotIndicator.position.copy(I.location); } }; let drop = e => { this.dispatchEvent({type: 'end'}); }; let onMouseUp = e => { this.camStart = null; this.pivot = null; this.pivotIndicator.visible = false; }; let scroll = (e) => { this.wheelDelta += e.delta; }; let dblclick = (e) => { this.zoomToLocation(e.mouse); }; this.addEventListener('drag', drag); this.addEventListener('drop', drop); this.addEventListener('mousewheel', scroll); this.addEventListener('mousedown', onMouseDown); this.addEventListener('mouseup', onMouseUp); this.addEventListener('dblclick', dblclick); } setScene (scene) { this.scene = scene; } zoomToLocation (mouse) { let camera = this.scene.camera; let I = Potree.utils.getMousePointCloudIntersection( mouse, camera, this.renderer, this.scene.pointclouds); if (I === null) { return; } let nmouse = { x: +(mouse.x / this.renderer.domElement.clientWidth) * 2 - 1, y: -(mouse.y / this.renderer.domElement.clientHeight) * 2 + 1 }; let targetRadius = 0; { let minimumJumpDistance = 0.2; let vector = new THREE.Vector3(nmouse.x, nmouse.y, 0.5); vector.unproject(camera); let direction = vector.sub(camera.position).normalize(); let ray = new THREE.Ray(camera.position, direction); let nodes = I.pointcloud.nodesOnRay(I.pointcloud.visibleNodes, ray); let lastNode = nodes[nodes.length - 1]; let radius = lastNode.getBoundingSphere().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; var animationDuration = 600; var 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) { let view = this.scene.view; let fade = Math.pow(0.5, this.fadeFactor * delta); let progression = 1 - fade; let camera = this.scene.camera; // compute zoom if (this.wheelDelta !== 0) { let I = Potree.utils.getMousePointCloudIntersection( this.viewer.inputHandler.mouse, this.scene.camera, this.renderer, this.scene.pointclouds); if (I) { let resolvedPos = new THREE.Vector3().addVectors(view.position, this.zoomDelta); let distance = I.location.distanceTo(resolvedPos); let jumpDistance = distance * 0.2 * this.wheelDelta; let targetDir = new THREE.Vector3().subVectors(I.location, view.position); targetDir.normalize(); resolvedPos.add(targetDir.multiplyScalar(jumpDistance)); this.zoomDelta.subVectors(resolvedPos, view.position); { let distance = resolvedPos.distanceTo(I.location); view.radius = distance; let speed = view.radius / 2.5; this.viewer.setMoveSpeed(speed); } } } // apply zoom if (this.zoomDelta.length() !== 0) { let p = this.zoomDelta.clone().multiplyScalar(progression); let newPos = new THREE.Vector3().addVectors(view.position, p); view.position.copy(newPos); } if (this.pivotIndicator.visible) { let distance = this.pivotIndicator.position.distanceTo(view.position); let pixelHeight = this.renderer.domElement.clientHeight; let pr = Potree.utils.projectedRadius(1, camera.fov * Math.PI / 180, distance, pixelHeight); let scale = (10 / pr); this.pivotIndicator.scale.set(scale, scale, scale); } // decelerate over time { this.zoomDelta.multiplyScalar(fade); this.wheelDelta = 0; } } };