potree
Version:
WebGL point cloud viewer - WORK IN PROGRESS
265 lines (202 loc) • 6.84 kB
JavaScript
/**
* @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
*
*
*
*/
Potree.OrbitControls = class OrbitControls extends THREE.EventDispatcher {
constructor (viewer) {
super();
this.viewer = viewer;
this.renderer = viewer.renderer;
this.scene = null;
this.sceneControls = new THREE.Scene();
this.rotationSpeed = 5;
this.fadeFactor = 10;
this.yawDelta = 0;
this.pitchDelta = 0;
this.panDelta = new THREE.Vector2(0, 0);
this.radiusDelta = 0;
this.tweens = [];
let drag = (e) => {
if (e.drag.object !== null) {
return;
}
if (e.drag.startHandled === undefined) {
e.drag.startHandled = true;
this.dispatchEvent({type: 'start'});
}
let ndrag = {
x: e.drag.lastDrag.x / this.renderer.domElement.clientWidth,
y: e.drag.lastDrag.y / this.renderer.domElement.clientHeight
};
if (e.drag.mouse === Potree.MOUSE.LEFT) {
this.yawDelta += ndrag.x * this.rotationSpeed;
this.pitchDelta += ndrag.y * this.rotationSpeed;
this.stopTweens();
} else if (e.drag.mouse === Potree.MOUSE.RIGHT) {
this.panDelta.x += ndrag.x;
this.panDelta.y += ndrag.y;
this.stopTweens();
}
};
let drop = e => {
this.dispatchEvent({type: 'end'});
};
let scroll = (e) => {
let resolvedRadius = this.scene.view.radius + this.radiusDelta;
this.radiusDelta += -e.delta * resolvedRadius * 0.1;
this.stopTweens();
};
let dblclick = (e) => {
this.zoomToLocation(e.mouse);
};
let previousTouch = null;
let touchStart = e => {
previousTouch = e;
};
let touchEnd = e => {
previousTouch = e;
};
let touchMove = e => {
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();
}
previousTouch = e;
};
this.addEventListener('touchstart', touchStart);
this.addEventListener('touchend', touchEnd);
this.addEventListener('touchmove', touchMove);
this.addEventListener('drag', drag);
this.addEventListener('drop', drop);
this.addEventListener('mousewheel', scroll);
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();
}
}
stopTweens () {
this.tweens.forEach(e => e.stop());
this.tweens = [];
}
update (delta) {
let view = this.scene.view;
{ // 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 px = -this.panDelta.x * panDistance;
let py = this.panDelta.y * panDistance;
view.pan(px, py);
}
{ // apply zoom
let progression = 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);
view.radius = radius;
view.position.copy(position);
}
{
let speed = view.radius / 2.5;
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;
}
}
};